Cooperative termination mode: drain teardown instead of aborting - #182
Draft
clholgat wants to merge 1 commit into
Draft
Cooperative termination mode: drain teardown instead of aborting#182clholgat wants to merge 1 commit into
clholgat wants to merge 1 commit into
Conversation
📊 PR Size: size/MTotal changes: 141 lines (6 files) Top files changed:
Size calculated as additions + deletions. Labels: XS (<10), S (<50), M (<250), L (<1000), XL (1000+) |
|
| Test Suite | Result |
|---|---|
| macOS: C++ & Platform Tests | ✅ success |
| Linux: Build & Export | ✅ success |
| API Surface Check | ✅ success |
| Snapshot Tests | ✅ success |
| Valdi Smoke Tests | ✅ success |
| valdi_web Integration Test | ✅ success |
| Linux: C++ Tests | ❌ failure |
| Linux: Module Tests | ✅ success |
| Test Coverage Delta | ✅ success |
| Linux: Build Compiler | ✅ success |
| Linux: Registry Validation | ✅ success |
| Linux: Hotreload Smoke | ✅ success |
Some tests failed. Please check the workflow logs for details.
🚀 Bazel remote cache is now enabled - future builds will be faster!
Workflow: Valdi CI
clholgat
force-pushed
the
cholgate/teardown-race-rootcause
branch
from
August 28, 2026 23:01
19d02b6 to
e47b9c2
Compare
Sensitive Files DetectedThis is an automated notice. A maintainer will review after import. |
Aggressive teardown flips _isDisposed from another thread and force-terminates JS execution, aborting in-flight work and racing the JS thread. Add a mode flag (default cooperative) that drains instead: - Host: makeJsThreadDispatchFunction no longer skips work just because _isDisposed is set; in-flight/queued JS-thread work runs (context still alive, teardown serialized after it), then teardown destroys the context and later calls hit the liveness check. - Worker: terminate()/dtor skip requestExecutionTermination and drain like self.close(). The mode is held on JavaScriptRuntime and pushed from the runtime tweak; worker runtimes pull it in postInit (they inherit the host's listener, not the pushed tweak), so a host override to aggressive reaches them too. Set false for aggressive termination (stops even frozen JS, at the cost of the teardown races). Draft for discussion, not for merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
clholgat
force-pushed
the
cholgate/teardown-race-rootcause
branch
from
August 28, 2026 23:55
e47b9c2 to
85c4703
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft for discussion, not for merge. Updated to the cooperative-mode approach (replaces the earlier dispatch-guard version on this branch).
Problem
Aggressive teardown flips
_isDisposedfrom another thread and force-terminates JS execution, aborting in-flight work and racing the JS thread. That's a large blast radius of teardown crashes / UB, and most of it is on host/session-scoped runtimes torn down on logout / scope-exit (not just workers).Approach — a configurable mode, default cooperative
One flag on the runtime; cooperative mode drains instead of aborting:
makeJsThreadDispatchFunctionno longer skips work just because_isDisposedis set. In-flight and already-queued JS-thread work runs (the context is still alive, since teardown is serialized after it on the serial queue), then teardown destroys the context and later calls are refused by the liveness check. This effectively restores the pre-aggressive ordering.terminate()/dtor skiprequestExecutionTermination()and drain likeself.close().Set the flag false for aggressive termination (stops even frozen JS, at the cost of the teardown races), so the aggressive path stays available and can be rolled out again safely once the root cause is fully addressed.
Open question
This mitigates by reverting to cooperative behavior. The known trade is the original one: cooperative can't force-stop a genuinely frozen JS worker (it drains, so a busy loop won't tear down). A bounded wait-then-escalate would preserve the frozen-JS guarantee while keeping well-behaved teardown safe. Feedback welcome on whether to build that here or in the deeper fix.
Tests
bzl test //valdi:test_integration: newcooperativeTeardownDrainsInFlightWorkAggressiveSkipsIt(all 4 JS engines) asserts cooperative drains in-flight work and aggressive skips it; existing teardown and worker-termination tests stay green.