Repository navigation
fix(core): release queue slot on intervention drop/raise to unblock stop_when_idle - #8409
Open
xuan (yuee3) wants to merge 1 commit into
Open
xuan (yuee3) wants to merge 1 commit into
xuan (yuee3) wants to merge 1 commit into
Conversation
…top_when_idle When an intervention handler drops a message (returns DropMessage) or raises in SingleThreadedAgentRuntime._process_next(), the function returned early without calling self._message_queue.task_done(). The queue's unfinished count never reached zero, so Queue.join() never completed and stop_when_idle() hung forever. The normal processing paths (_process_send/_process_publish/ _process_response) already call task_done() on every exit path; the six intervention early-return paths (send/publish/response x drop/raise) were the only ones missing it. stop()/stop_when_idle()/stop_when() replace self._message_queue only after the run-loop task completes, and _process_next() is awaited by that loop, so self._message_queue still refers to the queue the envelope was fetched from at these points; calling task_done() there is safe. Adds regression tests that call stop_when_idle() (with a fail-fast timeout) after intervention drop/raise on all three message kinds, including new coverage for the publish path, which had no drop/raise tests.
Author
|
@microsoft-github-policy-service agree |
This branch has not been deployed
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
Fixes a deadlock in
SingleThreadedAgentRuntime.stop_when_idle(): when an intervention handler drops a message (returnsDropMessage) or raises, the message queue's unfinished count is never decremented, soQueue.join()never completes andstop_when_idle()hangs forever.This continues the work started in #7642, which contained the same core fix but was closed for process reasons (not
wontfix). This PR reapplies the substantive fix and adds regression tests.Root cause
In
_process_next(), the three intervention-handler blocks (send / publish / response) have six early-return paths —DropMessageand exception, for each kind:future.set_exception(e)/future.set_exception(MessageDroppedException()), thenreturnreturnfuture.set_exception(e)/future.set_exception(MessageDroppedException()), thenreturnAll six return without calling
self._message_queue.task_done(). The envelope was already consumed viaqueue.get(), so the queue's unfinished task count leaks one slot per dropped/failed message.stop_when_idle()awaits_message_queue.join(), which only returns when that count reaches zero → permanent hang.Every other exit path in the same file already calls
task_done()(in_process_send,_process_publish,_process_response), so the intervention paths are the only ones missing it.Note: the queue cannot be swapped under our feet here —
stop()/stop_when_idle()/stop_when()replaceself._message_queueonly after the run-loop task completes, and_process_next()is awaited by that loop, soself._message_queuestill refers to the queue the envelope was fetched from. (Open PRs #7963/#8177 address a different race — in-flight background tasks outlivingstop()— and do not touch these paths.)Changes
_single_threaded_agent_runtime.py: callself._message_queue.task_done()before each of the six early returns (+6 lines).tests/test_intervention.py: switch the existing intervention drop/raise tests fromstop()tostop_when_idle()behind a fail-fast timeout helper, and addtest_intervention_drop_publish/test_intervention_raise_exception_on_publish(the publish path had no drop/raise coverage).Verification
DropMessagehandler,stop_when_idle()underasyncio.wait_for):BUG CONFIRMED: stop_when_idle() hung forever (Queue.join() never completes)NO BUG: stop_when_idle() returnedtest_intervention_drop_sendfails fast withFailed: stop_when_idle() did not return in time...; with the fix all tests pass.pytest tests/test_intervention.py tests/test_runtime.py→ 22 passed (Python 3.12, editable install of this commit).