Skip to content

fix(worker): leave the inspector pause loop when the worker is terminating - #2071

Open
adrian-niculescu wants to merge 4 commits into
NativeScript:mainfrom
adrian-niculescu:fix/worker-terminate-while-paused
Open

adrian-niculescu wants to merge 4 commits into
NativeScript:mainfrom
adrian-niculescu:fix/worker-terminate-while-paused

Conversation

@adrian-niculescu

@adrian-niculescu adrian-niculescu commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

In a debug build, a worker paused at a breakpoint inside console.log (for example a debugger statement in a getter that the message text conversion runs) makes the parent's worker.terminate() block until the debugger resumes, freezing the parent's thread.

WorkerWrapper::ConsoleLog holds inspectorMutex_ across WorkerInspectorClient::consoleLog, so the pause loop runs with that mutex held. Terminate() ends a pause through NotifyTerminating(), which it reaches by taking the same mutex, so it waits for the pause, and the pause only waits for the debugger. The pause loop now also leaves on the worker's own isTerminating_ flag, which Terminate() sets before it takes the mutex and which the loop checks on each pass while it waits. The paused worker then returns from consoleLog, the mutex is released, and Terminate() continues.

This builds on #2067, whose commits are the first three here. Leaving the pause on the flag lets the worker run on to its own teardown while the parent may still be interrupting its isolate, and #2067 is what keeps the isolate alive until the parent is done with it.

With the pause entered by hand at that point, the parent's terminate() on main blocks in mutex::lock() while the worker sits in runMessageLoopOnPause, and with this change it returns and the worker ends. Reproducing it for real needs a DevTools session paused inside the getter, so there is no spec for it. The full device suite passes.

Summary by CodeRabbit

  • Bug Fixes
    • Workers can now be terminated reliably after calling close(), including while paused in debugging.
  • Tests
    • Added coverage to verify that a closed worker stops running after termination.

Terminate() read the worker isolate and then interrupted it with no lock, while the worker thread could clear the pointer and dispose that isolate in the same window: a worker that ends through its own close() while its parent calls terminate(), or a parent that terminates its children during its own shutdown. Terminate() now holds a mutex across the read and the use, and the worker thread takes it when it withdraws the isolate, before disposing it.
close() only ends the worker once its running callback returns, and terminate() returned early for a closing worker, so a worker that kept running after close() could not be stopped. terminate() now interrupts it like any other running worker.
…spec in its timeout

A run where terminate() failed left the worker spinning past the spec. The loop now also checks a stop flag the spec raises in afterEach, the spec gets its own Jasmine timeout with a shorter start deadline, and the start-deadline branch fails through an expectation rather than the fail() global this Jasmine does not provide.
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: da43a519-319c-4acd-99f4-d6f799baafab
📥 Commits

Reviewing files that changed from the base of the PR and between 9b12329 and e8d3dab.

📒 Files selected for processing (7)
  • test-app/app/src/main/assets/app/mainpage.js
  • test-app/app/src/main/assets/app/tests/testWorkerTerminateAfterClose.js
  • test-app/app/src/main/assets/app/tests/workerCloseThenSpinWorker.js
  • test-app/runtime/src/main/cpp/WorkerInspectorClient.cpp
  • test-app/runtime/src/main/cpp/WorkerInspectorClient.h
  • test-app/runtime/src/main/cpp/WorkerWrapper.cpp
  • test-app/runtime/src/main/cpp/WorkerWrapper.h

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The worker runtime now permits termination after a worker begins closing and coordinates isolate access during termination and shutdown. A new test checks that the worker’s shared counter stops advancing after termination.

Changes

Worker termination

Layer / File(s) Summary
Coordinate termination and inspector shutdown
test-app/runtime/src/main/cpp/WorkerWrapper.h, test-app/runtime/src/main/cpp/WorkerWrapper.cpp, test-app/runtime/src/main/cpp/WorkerInspectorClient.h, test-app/runtime/src/main/cpp/WorkerInspectorClient.cpp
WorkerWrapper synchronizes isolate access during termination and shutdown. WorkerInspectorClient receives the worker termination flag and checks it in its pause loop.
Test termination after close
test-app/app/src/main/assets/app/tests/workerCloseThenSpinWorker.js, test-app/app/src/main/assets/app/tests/testWorkerTerminateAfterClose.js, test-app/app/src/main/assets/app/mainpage.js
The worker calls close() and increments a shared counter. The test terminates it and checks that the counter remains unchanged. The app loads the test module.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant WorkerTest
  participant workerCloseThenSpinWorker
  participant WorkerWrapper
  participant WorkerInspectorClient
  WorkerTest->>workerCloseThenSpinWorker: Send shared counter buffer
  workerCloseThenSpinWorker->>workerCloseThenSpinWorker: Call close and increment counter
  WorkerTest->>WorkerWrapper: Terminate worker
  WorkerWrapper->>WorkerWrapper: Interrupt isolate and notify event loop
  WorkerInspectorClient->>WorkerInspectorClient: Check termination flag and exit pause loop
  WorkerTest->>WorkerTest: Check that the counter remains unchanged
Loading

Suggested reviewers: edusperoni

Merge Risk: ⚪ Minimal · up to e8d3d

This change fixes a worker termination deadlock and allows a worker that has called close() to be terminated. No merge-blocking risk is evident from the supplied context.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 7 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: the inspector pause loop exits when the worker is terminating.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit watched the worker spin,
Then sent the stop signal in.
The counter paused, the loop grew still,
The test confirmed the change with skill.
One hop, one check, and all was done.

Comment @coderabbitai help to get the list of available commands.

…ating

A breakpoint hit while console.log converts its arguments pauses the worker inside ConsoleLog, which holds the worker's inspector mutex. terminate() could only end that pause through NotifyTerminating, which takes the same mutex, so the parent's terminate() blocked until the debugger resumed. The pause loop now also leaves on the worker's own termination flag, which terminate() sets before it takes the mutex.
@adrian-niculescu
adrian-niculescu force-pushed the fix/worker-terminate-while-paused branch from fb1b203 to e8d3dab Compare October 6, 2026 23:29
@adrian-niculescu
adrian-niculescu marked this pull request as ready for review October 6, 2026 23:32

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.

1 participant