Skip to content

fix(js/ts/python): synchronize cancellation registrations - #5036

Merged
MangelMaxime merged 5 commits into
mainfrom
fix/cancellation-registration-lifecycle
Oct 10, 2026
Merged

MangelMaxime merged 5 commits into
mainfrom
fix/cancellation-registration-lifecycle

Conversation

@dbrattli

@dbrattli dbrattli commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Python cancellation registration returns None, so callers cannot dispose listeners. Cancellation also iterates a mutable listener dictionary: callbacks can invalidate iteration, failures skip other listeners, and registration can race cancellation. JS retains completed registrations and fails to invoke late registrations. These behaviors differ from .NET and surfaced with published Fable/fable-library 5.19.0.

How

  • Return disposable Python registration handles and make repeated disposal safe, including callbacks disposing themselves or pending listeners.
  • Snapshot registrations newest first, claim each callback under the registry lock, invoke it outside the lock, and retire it even when it fails.
  • Make Python disposal wait for a callback running on another thread; registration after cancellation executes immediately without retaining a listener, including falsy and None state.
  • If a cancellation callback throws, continue running the remaining callbacks, then throw one exception containing all callback failures.
  • In JS, run cancellation callbacks newest first and invoke callbacks registered after cancellation immediately, matching .NET.
  • In Python, treat Boolean token arguments as the initial cancellation state; only integer arguments schedule cancellation. Previously, Python's bool subtype of int caused False and True to also schedule cancellation after 0 ms and 1 ms, respectively.
  • Add native registration/race regressions and the Python gate's native-test discovery. Source disposal keeps its existing no-op emulation.

Validation

  • Exact PR runtime: 6 Python tests passed; standalone JS registration/self-disposal/failure tests passed.
  • Executed .NET reference probes confirmed newest-first ordering, pending/self-disposal, immediate late state, aggregation, and waiting for running callbacks.
  • Combined integration gates passed: Python 2,511; JS 3,106 and Temporal JS 3,131; BEAM 2,746, plus their .NET gates. Pyright matched 34 errors/45 warnings; changed runtime/native test files have no diagnostics. Formatting and diff checks passed.
  • Published BEAM 5.19.0 cross-process cancellation was verified directly. Its atomics/registration broker remains unchanged.

@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Python Type Checking Results (Pyright)

Metric Value
Total errors 34
Files with errors 4
Excluded files 4
New errors ✅ No
Excluded files with errors (4 files)

These files have known type errors and are excluded from CI. Remove from pyrightconfig.ci.json as errors are fixed.

File Errors Status
temp/tests/Python/test_hash_set.py 18 Excluded
temp/tests/Python/test_applicative.py 12 Excluded
temp/tests/Python/test_nested_and_recursive_pattern.py 2 Excluded
temp/tests/Python/fable_modules/thoth_json_python/encode.py 2 Excluded

@dbrattli
dbrattli marked this pull request as ready for review October 3, 2026 21:51
@MangelMaxime
MangelMaxime merged commit 07db576 into main Oct 10, 2026
36 checks passed
@MangelMaxime
MangelMaxime deleted the fix/cancellation-registration-lifecycle branch October 10, 2026 15:26
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