Skip to content

Fix when_all to wait for all tasks before surfacing failures#173

Open
andystaples wants to merge 5 commits into
microsoft:mainfrom
andystaples:andystaples/fix-when-all-error-handling
Open

Fix when_all to wait for all tasks before surfacing failures#173
andystaples wants to merge 5 commits into
microsoft:mainfrom
andystaples:andystaples/fix-when-all-error-handling

Conversation

@andystaples

Copy link
Copy Markdown
Contributor

Summary

task.when_all() previously failed fast: as soon as one of its child tasks failed, the composite task was marked complete and the failure was surfaced immediately, even while sibling tasks were still running.

This does not match the .NET SDK (durabletask-dotnet), which relies on the framework's Task.WhenAll. That contract is: the returned task completes only after all supplied tasks finish, and then surfaces the first fault.

This PR changes WhenAllTask.on_child_completed to record the first exception but only complete once every child task has completed — surfacing the first failure at that point (or building the ordered result list if none failed).

Behavior change

An orchestration that fans out and hits a failure now waits for the remaining sibling tasks to finish before failing, instead of failing immediately. This is a deliberate change to match .NET semantics.

Changes

  • durabletask/task.pyWhenAllTask.on_child_completed no longer sets _is_complete on the first failure; it completes (with the first exception, if any) only after all children complete.
  • tests/durabletask/test_orchestration_executor.py — updated test_fan_in_with_single_failure to assert the orchestration keeps running (zero actions) while tasks are outstanding, then fails once all children complete.
  • CHANGELOG.md — added a FIXED entry.

Testing

  • pytest tests/durabletask/test_orchestration_executor.py — all pass
  • flake8 clean on changed files

when_all previously failed fast on the first child task failure. It now waits for every child task to complete before surfacing the first failure, matching the semantics of .NET's Task.WhenAll.
Copilot AI review requested due to automatic review settings July 14, 2026 17:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the core task.when_all() composite-task behavior in the Durable Task Python SDK to match .NET Task.WhenAll semantics by waiting for all child tasks to finish before completing and surfacing failures.

Changes:

  • Updated WhenAllTask.on_child_completed to delay completion until every child task finishes, recording the first failure to surface at the end.
  • Updated the fan-in unit test to assert the orchestration keeps running (no new actions) after an early failure until remaining tasks complete.
  • Added an Unreleased changelog entry documenting the behavior change.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
durabletask/task.py Updates WhenAllTask completion/failure timing to avoid fail-fast behavior.
tests/durabletask/test_orchestration_executor.py Adjusts test expectations to confirm orchestration remains running until all children complete, then fails.
CHANGELOG.md Documents the when_all() behavioral fix under Unreleased / FIXED.

Comment thread durabletask/task.py Outdated
Comment thread durabletask/task.py
Comment thread durabletask/task.py
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.

3 participants