Skip to content

Raise TaskFailedError from gather when a task exhausts retries#17

Merged
tcdent merged 2 commits into
mainfrom
task-failure-contract
Jul 11, 2026
Merged

Raise TaskFailedError from gather when a task exhausts retries#17
tcdent merged 2 commits into
mainfrom
task-failure-contract

Conversation

@tcdent

@tcdent tcdent commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • When a task exhausts its retries, the pool now writes a terminal TaskFailure record (task name, agent id, error, attempt count) to the task's result key, following the same key/serialize/set convention as the success path.
  • ax.get_result recognizes the record on its next poll and raises ax.TaskFailedError within ~0.5s, instead of polling into the void and raising a generic TimeoutError after the full timeout (default 300s).
  • ax.gather propagates the first failure via asyncio.gather — a single fail-fast contract, no return_exceptions path. Remaining tasks keep running in their workers and their results stay retrievable, so re-gathering survivors resolves finished tasks instantly.
  • TaskFailedError is exported on the ax namespace.

Design notes

  • Retries reuse the task's agent_id, so the failure record can only land after the retry budget is truly spent — a retry that succeeds still writes a normal result to the same key.
  • Raising does not cancel in-flight work; tasks in a gathered group are decoupled processes, and orphaned survivors are accepted by design.

Testing

  • get_result raises TaskFailedError with the full field set on the first poll (no timeout wait).
  • gather propagates a failure among successful tasks.
  • The pool's give-up branch stores a record that round-trips through backend.deserialize.
  • Full suite: 300 passed, 1 skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LC1fRUucUMCBWKwJFtq5YE

tcdent and others added 2 commits July 10, 2026 17:18
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LC1fRUucUMCBWKwJFtq5YE
Previously a permanently failed task left its result key empty, so
ax.gather and ax.get_result polled until their timeout (default 300s)
and raised a generic TimeoutError. Now the pool writes a TaskFailure
record to the result key when it gives up on a task, and get_result
raises ax.TaskFailedError (task_name, agent_id, error, attempts) on
the next poll. gather propagates the first failure via asyncio.gather;
other tasks keep running and their results remain retrievable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LC1fRUucUMCBWKwJFtq5YE
@tcdent
tcdent merged commit 749928f into main Jul 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant