Skip to content

Python: discard pending State on failed/cancelled superstep (#7859) - #8306

Open
LI (ktz03) wants to merge 5 commits into
microsoft:mainfrom
ktz03:fix/discard-pending-state-on-failed-superstep
Open

Python: discard pending State on failed/cancelled superstep (#7859)#8306
LI (ktz03) wants to merge 5 commits into
microsoft:mainfrom
ktz03:fix/discard-pending-state-on-failed-superstep

Conversation

@ktz03

@ktz03 LI (ktz03) commented Sep 11, 2026

Copy link
Copy Markdown

Motivation & Context

State.set() stages writes in _pending, but a failed or cancelled superstep previously left those writes intact. Because a Workflow reuses the same runner/state across run() calls, a later successful run could commit() stale pending writes from a prior failed/cancelled superstep.

Fixes #7859.

Description & Review Guide

  • What are the major changes? Discard pending State on fail/cancel (including finally so raising executor cleanup cannot skip it); defer executor_failed yields until after discard; block Workflow.run reuse while cleanup is in progress; lock cancel_pending_requests with the same active/cleanup hold as run().
  • What is the impact of these changes? Failed/cancelled/dropped streams cannot leak staged state into a later run.
  • What do you want reviewers to focus on? RunnerImpl.run_until_convergence cleanup ordering and Workflow.cancel_pending_requests / _is_run_active.

Related Issue

Fixes #7859

No other open PR targets this issue.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Call State.discard() on runner failure and cancellation paths so staged
writes cannot leak into a later successful run on the same Workflow.

Fixes microsoft#7859.

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.

🟡 Changes recommended

Cleanup can still be skipped during event streaming and cancellation outside the polling block.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Prevents failed workflow supersteps from leaking staged Python state into later runs.

Changes:

  • Discards pending state on failure and cancellation paths.
  • Adds a workflow-reuse regression test for failures.
File summaries
File Description
_runner.py Adds pending-state cleanup paths.
test_runner.py Tests state isolation after failure.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread python/packages/core/agent_framework/_workflows/_runner.py Outdated
Comment thread python/packages/core/agent_framework/_workflows/_runner.py Outdated
Comment thread python/packages/core/tests/workflow/test_runner.py
- Scope cancel/BaseException cleanup across the full superstep until commit
- Discard pending state before yielding failure events
- Add cancellation regression that stages state then reuses the workflow
@ktz03
LI (ktz03) deployed to github-app-auth September 12, 2026 11:19 — with GitHub Actions Active
Comment thread python/packages/core/agent_framework/_workflows/_runner.py
Comment thread python/packages/core/agent_framework/_workflows/_runner.py
- Discard in finally so raising executor cleanup cannot skip it
- Defer executor_failed yields until after discard
- Block Workflow.run reuse while superstep cleanup is in progress
@ktz03
LI (ktz03) deployed to github-app-auth September 14, 2026 11:57 — with GitHub Actions Active
- Discard in finally so raising executor cleanup cannot skip it
- Defer executor_failed yields until after discard
- Block Workflow.run reuse while superstep cleanup is in progress
@ktz03
LI (ktz03) deployed to github-app-auth September 14, 2026 12:35 — with GitHub Actions Active
Reject concurrent cancel/run while ResponseStream cleanup or another exclusive entry holds the workflow, and hold _exclusive_run_hold for the cancel continuation.
@ktz03
LI (ktz03) deployed to github-app-auth September 14, 2026 13:52 — with GitHub Actions Active
@ktz03
LI (ktz03) deployed to github-app-auth September 14, 2026 13:52 — with GitHub Actions Active
@ktz03

Copy link
Copy Markdown
Author

Eduard van Valkenburg (@eavanvalkenburg) Updated PR body to the repository template and addressed the latest review feedback on this head — please re-review when convenient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Pending State writes from a failed superstep leak into a later successful run

4 participants