Commit 346dcc3
fix: call task.uncancel() after catching CancelledError in shield loops (Python 3.11+) (#1523)
* fix: call task.uncancel() after catching CancelledError in shield loops
On Python 3.11+, asyncio.Task tracks a cancellation counter via
Task.cancelling()/Task.uncancel(). When CancelledError is caught
inside a while-True/asyncio.shield loop without calling uncancel(),
the counter stays elevated and Python re-throws CancelledError at
every subsequent await. This causes:
1. Duplicate commands (e.g. RequestCancelExternalWorkflow) sent to
the Temporal server
2. Spurious ERROR-level 'exception in shielded future' log lines
from temporalio.worker._workflow_instance
The fix adds task.uncancel() (guarded by hasattr for Python <=3.10
compatibility) after each CancelledError catch in all 6 affected
shield loops:
- run_activity() in _outbound_schedule_activity
- run_child() in _outbound_start_child_workflow
- start-wait loop in _outbound_start_child_workflow
- operation_handle_fn() in _outbound_start_nexus_operation
- start-wait loop in _outbound_start_nexus_operation
- _signal_external_workflow
Fixes #1504
* test: add coverage for task.uncancel() in shield loops
Add three integration tests to verify the fix for the elevated
cancellation counter issue on Python 3.11+ (cpython#93453):
- test_workflow_uncancel_shield_activity: Verifies that cancelling a
shielded activity does not produce duplicate cancel commands or
spurious 'exception in shielded future' error logs.
- test_workflow_uncancel_shield_child_workflow: Verifies that cancelling
a shielded child workflow task produces exactly one
RequestCancelExternalWorkflowExecution event in history (not
duplicates from the elevated cancellation counter).
- test_workflow_uncancel_shield_signal_external: Verifies that
signalling an external workflow completes without spurious error
logs from the shield loop.
Addresses review comment on PR #1523.
* test: add coverage for nexus operation shield loops
* style: apply ruff formatting fixes
* fix: use sys.version_info guard for task.uncancel() to satisfy type checkers
Replace hasattr(t, 'uncancel') with sys.version_info >= (3, 11) guard,
which is the established pattern in this file for version-specific APIs.
This satisfies pyright/mypy on Python 3.10 where asyncio.Task lacks uncancel().
---------
Co-authored-by: tconley1428 <tconley1428@gmail.com>1 parent 7ea54e6 commit 346dcc3
3 files changed
Lines changed: 328 additions & 47 deletions
File tree
- temporalio/worker
- tests
- nexus
- worker
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1924 | 1924 | | |
1925 | 1925 | | |
1926 | 1926 | | |
| 1927 | + | |
| 1928 | + | |
| 1929 | + | |
| 1930 | + | |
| 1931 | + | |
| 1932 | + | |
| 1933 | + | |
1927 | 1934 | | |
1928 | 1935 | | |
1929 | 1936 | | |
| |||
2008 | 2015 | | |
2009 | 2016 | | |
2010 | 2017 | | |
| 2018 | + | |
| 2019 | + | |
| 2020 | + | |
| 2021 | + | |
| 2022 | + | |
| 2023 | + | |
| 2024 | + | |
2011 | 2025 | | |
2012 | 2026 | | |
2013 | 2027 | | |
| |||
2025 | 2039 | | |
2026 | 2040 | | |
2027 | 2041 | | |
| 2042 | + | |
| 2043 | + | |
| 2044 | + | |
| 2045 | + | |
| 2046 | + | |
| 2047 | + | |
| 2048 | + | |
2028 | 2049 | | |
2029 | 2050 | | |
2030 | 2051 | | |
| |||
2053 | 2074 | | |
2054 | 2075 | | |
2055 | 2076 | | |
| 2077 | + | |
| 2078 | + | |
| 2079 | + | |
| 2080 | + | |
| 2081 | + | |
| 2082 | + | |
| 2083 | + | |
2056 | 2084 | | |
2057 | 2085 | | |
2058 | 2086 | | |
| |||
2067 | 2095 | | |
2068 | 2096 | | |
2069 | 2097 | | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
2070 | 2105 | | |
2071 | 2106 | | |
2072 | 2107 | | |
| |||
2599 | 2634 | | |
2600 | 2635 | | |
2601 | 2636 | | |
| 2637 | + | |
| 2638 | + | |
| 2639 | + | |
| 2640 | + | |
| 2641 | + | |
| 2642 | + | |
| 2643 | + | |
2602 | 2644 | | |
2603 | 2645 | | |
2604 | 2646 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| 13 | + | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
| |||
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
23 | | - | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
268 | 270 | | |
269 | 271 | | |
270 | 272 | | |
271 | | - | |
272 | | - | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | | - | |
279 | | - | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
280 | 286 | | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
285 | | - | |
286 | | - | |
287 | | - | |
288 | | - | |
289 | | - | |
290 | | - | |
291 | | - | |
292 | | - | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
293 | 299 | | |
294 | | - | |
295 | | - | |
296 | | - | |
297 | | - | |
298 | | - | |
299 | | - | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
312 | | - | |
313 | | - | |
314 | | - | |
315 | | - | |
316 | | - | |
317 | | - | |
318 | | - | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
319 | 339 | | |
320 | 340 | | |
321 | 341 | | |
| |||
0 commit comments