fix(server): release the ActiveTask after a direct Message response - #1297
Open
christophstach wants to merge 1 commit into
Open
christophstach wants to merge 1 commit into
christophstach wants to merge 1 commit into
Conversation
A direct Message is a complete response without task tracking (spec 3.1.1, 3.1.2), so no follow-up can continue it. DefaultRequestHandlerV2 still kept the request's ActiveTask alive: the producer stayed parked on the request queue and the consumer and both dispatchers waited with it, so every message-only request left four pending asyncio tasks and a registry entry behind until the process exited. After forwarding the Message to subscribers, the consumer now finishes the ActiveTask the same way it does for a terminal task state, which releases the producer, consumer, queues and registry entry.
🧪 Code Coverage (vs
|
| Base | PR | Delta | |
|---|---|---|---|
| src/a2a/server/agent_execution/active_task.py | 95.02% | 95.11% | 🟢 +0.08% |
| Total | 92.95% | 92.95% | 🟢 +0.01% |
Generated by coverage-comment.yml
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.
Description
A direct
Messageis a complete response for interactions that do not need task tracking (spec §3.1.1: the agent "MAY return a directMessageresponse for simple interactions"; §3.1.2: a message-only stream provides "No task tracking or updates"). No follow-up can continue such a request.DefaultRequestHandlerV2still kept the request'sActiveTaskalive after aMessageresponse:self._request_queue.get();EventQueueSource._dispatch_looptasks wait with it;ActiveTaskRegistry.Every message-only request therefore leaves four pending asyncio tasks behind until the process exits. In a long-running server, the pending task count grows linearly with traffic.
Fix
After the consumer forwards the
Messageto subscribers, it finishes theActiveTaskthe same way it already does for a terminal task state: it sets_is_finishedand shuts down the request queue (_handle_terminal_state). The producer then leaves its loop and closes the event queues, the consumer drains and exits, and_maybe_cleanupremoves the registry entry.The
Messageis enqueued to subscribers before the shutdown, soon_message_sendandon_message_send_streamstill receive it.Out of scope: input-required tasks stay parked for a follow-up, as covered by
test_cancel_of_input_required_task_cannot_be_undone. This PR does not change that.Tests
Two new tests in
tests/server/request_handlers/test_default_request_handler_v2.pydrive the real handler with an executor that answers with a singleMessage:test_on_message_send_message_response_releases_active_task: 3 ×on_message_send, then no pending asyncio tasks and an empty registry;test_on_message_send_stream_message_response_releases_active_task: a message-only stream yields exactly oneMessage, then the same assertions.Both fail on
main(leftoverActiveTask._run_producer,ActiveTask._run_consumerandEventQueueSource._dispatch_loop) and pass with the fix.Standalone repro, 50 requests each, counting pending asyncio tasks afterwards:
Checks
./scripts/lint.sh: passed. The 3tywarnings are pre-existing, inclient_factory.pyandclient/transports/__init__.py.uv run pytest: 2173 passed, 181 skipped, 3 xfailed, 1 xpassed.uv run pytest --cov=src: total 93 %,active_task.py95 %; the new lines are covered.Fixes #1296