Skip to content

fix(core): unpublish a pool worker's inbox on every stop (#346) - #373

Merged
EdmondDantes merged 3 commits into
mainfrom
fix/pool-worker-self-stop
Oct 1, 2026
Merged

EdmondDantes merged 3 commits into
mainfrom
fix/pool-worker-self-stop

Conversation

@EdmondDantes

Copy link
Copy Markdown
Contributor

Closes #346.

A handler's $server->stop() on a reactor-pool worker stopped that worker's clone and left its request inbox in the worker registry, so the reactors kept routing HTTP/3 requests to it, and the clone ran them after the stop, with isRunning() false, in the scope start() was draining. do_stop now unpublishes the inbox on every stop. start() fences the reactors after its wait (the retire the pool path already ran), and waits out a retire the pool coroutine still has in flight instead of freeing the server under it. The bailout and failed-wait exits, which cannot fence, unpublish before the free, and start() does not publish when a stop already waits.

The second case of the issue, a clone started again with the old inbox, is unreachable: the pool loads a fresh clone per worker run and starts it once, and a start() from the clone's own handler throws before the inbox is published.

Evidence.

  • h3/079 (requests after a handler's stop): on main 6 to 10 of 16 answered STOPPED, 3 runs of 3; passes with the fix.
  • h3/080 (requests sent while the stopping handler holds its thread for 1 s): on main 6 to 7 of 16 answered STOPPED, 3 runs of 3; passes with the fix, and checks that answers arrive inside the window.
  • Mutants: dropping the unpublish in do_stop fails h3/080 (2 runs of 2 over the 19 local pool tests). Dropping the fence in start() passes all of them: it covers a dispatch that loaded the inbox just before the unpublish, which no test widens.
  • Local suite -j4: 522 of 525 run passed, 25 skipped. The 3 failures, h1/062 to h1/064, fail on main the same way: the local PHP binary was built on 2026-09-26, before Pause a stopped listen event instead of accepting through it (#305) php-async#306, which they need.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Coverage

Total lines: 83.91% → 83.97% (+0.06 pp)

File Baseline Current Δ Touched
src/core/worker_registry.c 77.91% 79.07% +1.16 pp
src/http1/http_parser.c 87.58% 87.98% +0.41 pp
src/http3/http3_callbacks.c 86.28% 86.38% +0.10 pp
src/http3/http3_dispatch.c 88.08% 88.30% +0.22 pp
src/http3/http3_listener.c 76.76% 78.56% +1.80 pp
src/http_server_class.c 76.02% 75.99% -0.03 pp ●
src/websocket/ws_session.c 89.71% 89.89% +0.18 pp

@EdmondDantes
EdmondDantes merged commit df28cde into main Oct 1, 2026
8 checks passed
@EdmondDantes
EdmondDantes deleted the fix/pool-worker-self-stop branch October 1, 2026 09:03
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.

The reactor-pool worker inbox dispatches into the server scope after stop() and across a restart

1 participant