Repository navigation
fix: retain subprocess ownership after waiter cancellation - #3308
Conversation
|
Resolve by running |
|
merge-train: ejected from this batch — rides the next train once fixed. |
tests/registry.json rebuilt from the merge stages: dev's entries plus this branch's one new entry (unit/test_runtime_process_ownership.py). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts the result (Abilityai#3307) test_headless_worker_finish_racing_waiter_cancellation_still_cleans_up failed in CI (run 37567485053, Python 3.13.15) with "500: Task execution error: '<' not supported between instances of 'NoneType' and 'int'" instead of CancelledError. The test scheduled task.cancel() from the worker thread and let the worker return immediately, assuming a cancel queued first is always processed before the worker's result. Since CPython 3.13.12, asyncio's _chain_future copies the result synchronously when the done-callback is attached on the loop thread to an already-finished worker future, so run_in_executor hands back a completed future, the caller never yields, the queued cancel never lands, and the stub context goes through the real _finalize_headless_result (return_code None). Product cleanup is correct in that ordering; the test's timing assumption was not. The worker now waits until the cancel has been delivered, and the loop is held until the worker has fully returned, which pins the ordering the test names (worker never observes the abandoned flag, caller cancelled before its result) on every interpreter. No sleeps, no product change. Removing the caller's finally: unregister still fails the test 10/10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Pushed two commits to clear the merge-train ejection:
Root cause. CI failed with Reproduction, unmodified test, 40 runs: Python 3.13.5: 40 pass. Python 3.13.16: 25 pass, 15 fail with the exact CI error. (3.13.16 stands in for CI's 3.13.15.) Fix. The worker now waits until the cancel is delivered, and the loop callback holds the loop until the worker has returned, on a dedicated single-thread pool. No sleeps, skips or xfails; the cleanup assertions are unchanged, plus a control assert that the worker returned before the waiter's cleanup. Mutation check: removing the product's Results. Fixed test 50/50 on both 3.13.16 and 3.13.5; whole file green on 15 random seeds; 56 unit files touching |
…ebuilt, both entries kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…son rebuilt, all entries kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Description
Cancelling a chat or headless execution waiter can remove a still-running child from ProcessRegistry. If both termination waits time out, the registry also reports success without observing exit. Both defects reproduce on unmodified dev a72271d.
Retain registered live children, their log subscriptions and sweep allowlist entries until exit is observed. After cancellation or outer timeout, executor workers perform eventual cleanup; ordinary success still finalizes the result before stream_end. Chat readers are shielded because their child already exists, while queued headless workers remain cancellable before spawning. Unconfirmed termination now returns an explicit failure and retains the handle.
Architecture documentation and the test registry describe this contract. This does not establish distributed capacity enforcement, pre-Popen ownership, reused-ID safety, descendant-process termination, or server-restart recovery.
Fixes #3307
Journey Impact: extends: J04
Validation and review
Reproduce the final focused suite with normal backend test dependencies and the agent source on PYTHONPATH:
Tested with Python 3.13 in an isolated Linux container. Real container restart, production dispatch and whole-stack acceptance are not claimed.
Mutation: test_abandoned_waiter_keeps_live_subprocess_owned and test_terminate_does_not_confirm_a_process_that_survived_both_waits fail against stock; the former also fails with stock executors over the corrected registry and without timeout abandonment cleanup.
Checklist