fix(ipc): close supervised process when start() is cancelled - #6051
Merged
Conversation
When the owning task is cancelled while awaiting start(), the shielded _start() keeps running and creates the supervise task afterwards, but aclose() no-ops because the proc isn't marked started yet. This leaks the supervise task and the child process, and can hang worker shutdown (surfaced as a flaky teardown failure of test_slow_initialization on slow CI runners). aclose() now waits for the in-flight _start() before checking started, and kills the process when it was never initialized: the child reads InitializeRequest before servicing any other message, so a graceful ShutdownRequest could never be acked. kill() resolves the pending initialize future so the supervise task can observe the process exit.
speed_factor no longer buys wall-clock time now that the session tests run under virtual time, so set it to 1 and raise the default drain_delay to 5s for more headroom at no cost.
theomonnom
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
test_slow_initializationflakes on CI with a leakedProcJobExecutor._supervise_taskat teardown. The root cause is a real shutdown race inSupervisedProc, not a test issue.When the owning task (e.g.
ProcPool._proc_spawn_taskduring pool close) is cancelled while awaitingstart(), the shielded_start()keeps running and creates the supervise task afterwards. The cleanup path then callsaclose(), which no-ops because the proc isn't marked started yet — leaking the supervise task and the child process. The orphaned child blocks forever waiting forInitializeRequest, and its non-daemon join thread can hang worker shutdown indefinitely.Changes
start()keeps a handle on the shielded_start()task;aclose()waits for it before checkingstarted, so an abandoned start can't race past the check.aclose()kills a never-initialized process instead of attempting a graceful shutdown: the child readsInitializeRequestbefore servicing any other message, so aShutdownRequestcould never be acked.kill()resolves a pending_initialize_futso the supervise task (which waits on it before supervising) can observe the process exit.test_aclose_after_cancelled_start, which deterministically reproduces the leak (fails the leaked-tasks check and hangs pytest exit without the fix).nit: Also sets the agent session tests to
speed = 1and raises the defaultdrain_delay— they run under virtual time, so the speed factor no longer buys wall-clock time.