Skip to content

Report an activity's outcome even when a cancel lands during encoding - #1910

Open
DABH wants to merge 3 commits into
mainfrom
fix/activity-cancel-during-result-encode
Open

DABH wants to merge 3 commits into
mainfrom
fix/activity-cancel-during-result-encode

Conversation

@DABH

@DABH DABH commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

What was changed

_run_activity marks the activity done as soon as its code returns or raises, before encoding the result or failure, so _RunningActivity.cancel() no longer cancels the task while the outcome is being reported. wait_all_completed collects the activity tasks' exceptions instead of letting one escape, as its comment already promised. A regression test uses a payload codec that yields during encode. CHANGELOG entry under Unreleased.

Why

A Core-issued cancel (workflow cancel, heartbeat failure, or worker shutdown with the default zero grace period) that landed while encode or encode_failure was awaiting raised CancelledError past the handler's except Exception, so complete_activity_task was never called. Core kept the activity outstanding, wait_all_completed never returned and worker.shutdown() hung. Found while reviewing #1837, whose eviction-side cause is moving to sdk-core.

Testing

The new test fails on main with a 20s shutdown timeout and passes with the fix; its captured log shows the WORKER_SHUTDOWN cancel landing mid-encode. Neighbouring shutdown tests pass, also with four workers. poe lint, pyright, mypy and basedpyright clean.

_RunningActivity.cancel() already skips cancelling the task once the
activity is done, but done was only set after the result or failure had
been encoded. A cancel from Core (workflow cancel, heartbeat failure, or
worker shutdown with the default zero grace period) that arrived while
encode() or encode_failure() was awaiting raised CancelledError past the
handler's except Exception, so complete_activity_task was never called.
Core kept the activity outstanding, wait_all_completed never returned
and worker.shutdown() hung.

Mark the activity done as soon as its code returns or raises, before
encoding, and make wait_all_completed collect task exceptions so it
keeps its no-raise contract. Add a regression test with a codec that
yields during encode; it fails on main with a 20s shutdown timeout.
@DABH
DABH requested a review from a team as a code owner October 1, 2026 05:57
@DABH
DABH requested a balanced review from Copilot October 1, 2026 06:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The regression test uses a timing-dependent sleep that does not guarantee cancellation occurs during encoding.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Ensures completed activity outcomes survive cancellation during asynchronous encoding and prevents shutdown task exceptions from escaping.

Changes:

  • Marks activity execution complete before encoding its outcome.
  • Collects and logs shutdown-time task exceptions.
  • Adds regression coverage and a changelog entry.
File Description
temporalio/​worker/​_activity.py Protects outcome reporting and hardens shutdown waiting.
tests/​worker/​test_activity.py Adds cancellation-during-encoding coverage.
CHANGELOG.md Documents the fix.

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

Comment thread tests/worker/test_activity.py Outdated
A fixed sleep in encode let a slow enough cancel arrive after encoding
had finished, in which case an unfixed worker would also pass. The codec
now blocks until the test has seen the "Cancelling activity" log, which
the cancel handler emits in the same synchronous block as cancel().

This branch has not been deployed

No deployments
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.

2 participants