Repository navigation
fix(server): record executor failures through the event consumer - #1366
Merged
Iwaniukooo11 merged 3 commits intoOct 23, 2026
Merged
Conversation
When an executor enqueued its Task and raised before that Task was saved, the producer's failure write and the consumer's save both inserted the same row. With DatabaseTaskStore one insert failed: the request returned the SUBMITTED task as a success, or raised IntegrityError in place of the executor's error. The producer now enqueues a _RequestFailed event and the consumer writes FAILED when it dequeues it, after the events the executor enqueued first. The fallback task is still created when the executor never made one, FAILED is stamped with the failure time, and the write still lands when the agent answered with a Message. Fixes a2aproject#1351
🧪 Code Coverage (vs
|
| Base | PR | Delta | |
|---|---|---|---|
| src/a2a/server/agent_execution/active_task.py | 95.40% | 95.46% | 🟢 +0.07% |
| src/a2a/server/tasks/database_task_store.py | 92.47% | 95.16% | 🟢 +2.69% |
| Total | 92.90% | 92.96% | 🟢 +0.06% |
Generated by coverage-comment.yml
Iwaniukooo11
requested changes
Oct 22, 2026
The consumer now notes a producer failure when it dequeues the exception, since only the producer enqueues exceptions, and takes the context id for the fallback task from the task manager. The fallback path returns the task it created, and _write_failed_status documents its three cases.
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
When an executor enqueues its
Taskand raises before that Task is saved,_run_producerand the consumer both insert the same row through the sharedTaskManager. WithDatabaseTaskStoreone insert fails, and the request either returns theSUBMITTEDtask as a success or raisesIntegrityErrorinstead of the executor's error.This moves the failure write to
EventConsumer, as suggested on the issue:_run_producerno longer saves the failure. It only enqueues the exception, as before._write_failed_statuscreates the fallback task throughensure_task_id, with the context id from_task_manager.context_id, only when no task exists, which keeps the case fix: persist early producer failure as FAILED with originating message #1106 fixed. FAILED is stamped with the failure time, solast_updatedis set. The write goes through_handle_task_modification_eventrather than_handle_task_event, so it still lands when the agent answered with a Message.Visible differences from the old producer write:
last_updatedNULL.status.messageintohistory, as on any status update.history. The old write dropped it.Three tests are added. One holds the store's insert of the agent's Task until the executor has raised, which is the window a database round trip leaves open. It fails on
mainwithUNIQUE constraint failed: tasks.idand passes with this change. The other two check that a task which fails after reporting progress is stamped with the failure time, and that a follow-up answered with a Message still leaves the task FAILED.Checks on current
main(79a6f45), Python 3.10: the full suite passes with Postgres 18 behind the database tests (2396 passed, 92 skipped; the 4 cross-version tests timed out starting their servers in that run and pass on their own). I did not run the MySQL tests.ruff check,ruff format --checkandty checkshow nothing new.CONTRIBUTINGGuide.Fixes #1351