Skip to content

feat: implement workflow cancellation#128

Open
timl3136 wants to merge 7 commits into
cadence-workflow:mainfrom
timl3136:wf-cancallation-3
Open

feat: implement workflow cancellation#128
timl3136 wants to merge 7 commits into
cadence-workflow:mainfrom
timl3136:wf-cancallation-3

Conversation

@timl3136

@timl3136 timl3136 commented Jun 4, 2026

Copy link
Copy Markdown
Member

What changed?
implement workflow cancellation

Why?
Cancellation is a important feature that allows for gracefully exit

How did you test it?

Potential risks

Release notes

Documentation Changes

Comment thread cadence/_internal/workflow/statemachine/decision_manager.py
Comment thread cadence/_internal/workflow/workflow_engine.py
Signed-off-by: Tim Li <ltim@uber.com>
@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.54217% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...emachine/child_workflow_execution_state_machine.py 75.00% 0 Missing and 2 partials ⚠️
...internal/workflow/statemachine/decision_manager.py 92.00% 1 Missing and 1 partial ⚠️
...emachine/signal_external_workflow_state_machine.py 33.33% 2 Missing ⚠️
cadence/_internal/workflow/workflow_engine.py 83.33% 1 Missing and 1 partial ⚠️
...al/workflow/statemachine/activity_state_machine.py 75.00% 0 Missing and 1 partial ⚠️
.../workflow/statemachine/completion_state_machine.py 50.00% 1 Missing ⚠️
...al/workflow/statemachine/decision_state_machine.py 50.00% 1 Missing ⚠️
cadence/_internal/workflow/workflow_instance.py 75.00% 0 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
cadence/_internal/workflow/context.py 92.24% <100.00%> (+0.58%) ⬆️
...ernal/workflow/statemachine/timer_state_machine.py 95.83% <100.00%> (+0.27%) ⬆️
cadence/workflow.py 93.63% <100.00%> (+0.27%) ⬆️
...al/workflow/statemachine/activity_state_machine.py 98.43% <75.00%> (+1.71%) ⬆️
.../workflow/statemachine/completion_state_machine.py 87.50% <50.00%> (-5.36%) ⬇️
...al/workflow/statemachine/decision_state_machine.py 94.23% <50.00%> (-1.77%) ⬇️
cadence/_internal/workflow/workflow_instance.py 92.00% <75.00%> (+0.33%) ⬆️
...emachine/child_workflow_execution_state_machine.py 97.89% <75.00%> (-2.11%) ⬇️
...internal/workflow/statemachine/decision_manager.py 94.08% <92.00%> (+1.46%) ⬆️
...emachine/signal_external_workflow_state_machine.py 94.59% <33.33%> (-5.41%) ⬇️
... and 1 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@timl3136 timl3136 force-pushed the wf-cancallation-3 branch from 07d2c9f to a0876ea Compare June 9, 2026 21:58
timl3136 and others added 3 commits June 9, 2026 14:59
Signed-off-by: Tim Li <ltim@uber.com>
<!-- Describe what has changed in this PR -->
**What changed?**
update_schedule now uses a read-modify-write pattern (describe →
callback → full state update).

<!-- Tell your future self why have you made these changes -->
**Why?**
Server replaces the whole field on UpdateSchedule, so partial updates
would zero out sub-fields the caller didn't intend to change.

<!-- How have you verified this change? Tested locally? Added a unit
test? Checked in staging env? -->
**How did you test it?**
unit tests passing.

<!-- Assuming the worst case, what can be broken when deploying this
change to production? -->
**Potential risks**
N/A

<!-- Is it notable for release? e.g. schema updates, configuration or
data migration required? If so, please mention it, and also update
CHANGELOG.md -->
**Release notes**
N/A

<!-- Is there any documentation updates should be made for config,
https://cadenceworkflow.io/docs/operation-guide/setup/ ? If so, please
open an PR in https://github.com/cadence-workflow/cadence-docs -->
**Documentation Changes**
N/A

Signed-off-by: Abhishek Jha <abhishek.jha@uber.com>
Signed-off-by: Tim Li <ltim@uber.com>
<!-- Describe what has changed in this PR -->
**What changed?**
Updating idl to latest version

<!-- Tell your future self why have you made these changes -->
**Why?**
We have bunch of updated idl changes especially of schedule feature
which is required for schedule python client and testing

<!-- How have you verified this change? Tested locally? Added a unit
test? Checked in staging env? -->
**How did you test it?**
make pr

<!-- Assuming the worst case, what can be broken when deploying this
change to production? -->
**Potential risks**
N/A

<!-- Is it notable for release? e.g. schema updates, configuration or
data migration required? If so, please mention it, and also update
CHANGELOG.md -->
**Release notes**
N/A

<!-- Is there any documentation updates should be made for config,
https://cadenceworkflow.io/docs/operation-guide/setup/ ? If so, please
open an PR in https://github.com/cadence-workflow/cadence-docs -->
**Documentation Changes**
N/A

Signed-off-by: abhishek.jha <abhishek.jha@uber.com>
Signed-off-by: Tim Li <ltim@uber.com>
@timl3136 timl3136 force-pushed the wf-cancallation-3 branch from 0705678 to 492a415 Compare June 9, 2026 22:01
@gitar-bot

gitar-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 resolved / 2 findings

Implements workflow cancellation via new helper methods and integrated state machine support, addressing the propagation of cancellation signals to awaiters and optimizing assertion stability under performance flags.

✅ 2 resolved
Bug: Cancel message not propagated to timer/activity awaiters

📄 cadence/_internal/workflow/statemachine/decision_manager.py:276-280 📄 cadence/_internal/workflow/statemachine/timer_state_machine.py:46-60 📄 cadence/_internal/workflow/statemachine/activity_state_machine.py:52-66
request_cancel_pending_decisions(message) is meant to thread the cancellation cause through to coroutines awaiting pending operations via force_cancel(message). However, for timers and for activities in the REQUESTED state, the future is already cancelled without a message by the internal request_cancel() call before force_cancel(message) runs:

  • decision_manager.request_cancel_pending_decisions calls self._request_cancel(decision_id) (which invokes machine.request_cancel()) and then machine.force_cancel(message).
  • TimerStateMachine.request_cancel calls self.force_cancel() (no message) for both REQUESTED and RECORDED states, so the future is already done() and the subsequent force_cancel(message) is a no-op.
  • ActivityStateMachine.request_cancel calls self.force_cancel() (no message) in the REQUESTED state with the same effect.

As a result, a workflow that inspects e.args of the CancelledError raised at an await workflow.sleep(...) or pending await workflow.execute_activity(...) will not receive the cancellation cause, while child workflows (RECORDED activities) do. This is an inconsistency in the new feature rather than a crash; the included tests pass because they return constant strings and never read the message. Consider passing the message into request_cancel (or only calling force_cancel(message) and letting it drive state) so the cause is delivered uniformly.

Quality: assert on cancellation_info() may be stripped under -O

📄 cadence/_internal/workflow/workflow_engine.py:298-308 📄 cadence/_internal/workflow/context.py:242-255
In _handle_cancel_requested_input_event, the code does info = self._context.cancellation_info(); assert info is not None before dereferencing info.cause. When Python runs with -O (optimizations) assertions are removed, so this becomes an implicit assumption rather than a guard. While request_cancel(attrs) was just called and always populates _cancellation_info, relying on assert for control-flow correctness is fragile. Prefer an explicit check/raise or read the cause directly from attrs to avoid the round-trip through the context, e.g. self._decision_manager.request_cancel_pending_decisions(attrs.cause).

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

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