Skip to content

[codex] Make Swoole worker recycling cooperative#4

Open
adhikjoshi wants to merge 1 commit into
mainfrom
codex/cooperative-swoole-worker-recycle
Open

[codex] Make Swoole worker recycling cooperative#4
adhikjoshi wants to merge 1 commit into
mainfrom
codex/cooperative-swoole-worker-recycle

Conversation

@adhikjoshi
Copy link
Copy Markdown
Contributor

Summary

This PR changes HTTP worker max-request recycling from Swoole's built-in max_request path to an application-level cooperative recycle check that runs only after a request coroutine has unregistered itself.

Root cause

Production evidence showed a worker recycle overlapping an in-flight /api/v6/image_editing/qwen_edit request. The worker logged graceful shutdown, but Nginx still saw recv() failed (104: Connection reset by peer) from the upstream and returned 502. In coroutine mode, Swoole's built-in HTTP worker recycling can close the worker while another coroutine response is still being read upstream.

What changed

  • Forces HTTP max_request and max_request_grace to 0, even if low-level Swoole options try to re-enable them.
  • Keeps task worker task_max_request and task_max_request_grace unchanged.
  • Adds per-worker cooperative counters to WorkerState.
  • Adds StopWorkerIfMaxRequestsExceeded, which requests worker stop only when the max-request threshold has been reached and Monitor::getActiveRequestCount() is 0.
  • Wires the recycler in the request finally block after timer cleanup and request coroutine unregister.
  • Classmaps bin/WorkerState.php so typed source classes and the new action can resolve it outside the Swoole entrypoint's manual require path.
  • Adds unit coverage and a real Swoole HTTP server integration probe for serial, overlapping, and batched concurrent recycle cases.

Validation

  • /opt/homebrew/Cellar/[email protected]/8.3.29/bin/php vendor/bin/phpunit
    129 tests, 974 assertions passed. PHPUnit reports 11 existing deprecations.
  • /opt/homebrew/Cellar/[email protected]/8.3.29/bin/php vendor/bin/phpunit tests/Feature/SwooleCooperativeRecycleIntegrationTest.php
    3 tests, 107 assertions passed.
  • Repeated the real Swoole integration probe 5 consecutive times; all passed.
  • /opt/homebrew/Cellar/[email protected]/8.3.29/bin/php vendor/bin/phpstan analyse src/Swoole/Actions/StopWorkerIfMaxRequestsExceeded.php --level=8 --memory-limit=1G --no-progress passed.
  • /opt/homebrew/Cellar/[email protected]/8.3.29/bin/php /opt/homebrew/bin/composer validate --strict passed.
  • php vendor/bin/phpunit tests/Unit/StopWorkerIfMaxRequestsExceededTest.php with the default non-Swoole PHP binary passed.
  • Confirmed no leaked local Swoole probe processes after tests.

Notes for review

A broader PHPStan run over touched existing command/handler files still reports pre-existing baseline issues unrelated to this PR, including HigherOrderTapProxy::start(), OnWorkerStart::bootWorker() missing a static-analysis return, Redis::purge(), and narrowed function_exists() checks. The new action itself is clean at PHPStan level 8.

@adhikjoshi adhikjoshi marked this pull request as ready for review May 31, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant