fix(ext/node): keep worker alive while holding a refed MessagePort - #34877
Merged
Conversation
A node:worker_threads Worker that holds a "refed" transferable object such as a MessagePort (e.g. a worker pool's dedicated IPC port, or a worker that is set up and idle waiting for work) must not be terminated on idle. The runtime idle-termination check `hasMessageEventListener()` in `runtime/js/99_main.js` consults `messagePort.refedMessagePortsCount` to decide whether a node worker should stay alive. That counter is a mutable module-level `let` in `ext/web/13_message_port.js`. When ext/web was converted to lazy-loaded IIFE scripts in #33760, the module's real ESM `export { refedMessagePortsCount }` (a live binding) became a plain property on the returned object, which captured a one-time snapshot of `0`. As a result the refed-port branch of the idle check was dead and a worker kept alive only by a refed MessagePort (with no active "message" listener op) was incorrectly terminated on idle. Restore the live-binding behavior by exposing `refedMessagePortsCount` as a getter. Adds spec tests covering both a worker that receives delayed work over a refed port after an idle period, and a worker kept alive purely by a refed MessagePort it does not listen on. Closes #23169 Co-Authored-By: Divy Srivastava <me@littledivy.com>
littledivy
approved these changes
Jun 5, 2026
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.
Summary
A
node:worker_threadsWorker that holds a "refed" transferable object such as aMessagePortmust not be terminated on idle. This covers the use cases from #23169:MessagePortfor IPC, with a minimum number of workers always kept alive, andRoot cause
The runtime idle-termination check
hasMessageEventListener()inruntime/js/99_main.jsconsultsmessagePort.refedMessagePortsCountto decide whether a node worker should stay alive:That counter is a mutable module-level
letinext/web/13_message_port.js. When ext/web was converted to lazy-loaded IIFE scripts in #33760, the module's real ESMexport { refedMessagePortsCount }(a live binding) became a plain property on the returned object literal, capturing a one-time snapshot of0. The refed-port branch of the idle check was therefore dead, and a worker kept alive only by a refedMessagePort(with no active "message" listener op promise) was incorrectly terminated on idle.Fix
Restore the live-binding semantics by exposing
refedMessagePortsCountas a getter on the module's return object.Tests
Adds two spec tests under
tests/specs/node/worker_threads/:refed_messageport_idleâ a worker receives delayed work over a refed transferredMessagePortafter an idle period.refed_messageport_holderâ a worker kept alive purely by a refedMessagePortit does not listen on. This isolates the fix: it fails onmain(worker terminates on idle) and passes with the change.Closes #23169
Closes denoland/divybot#429