fix(ext/node): do not exit worker thread when there is pending async op (#27378)

This change fixes the premature exit of worker threads when there are still
remaining pending ops.

This change reuses the idea of #22647 (unref'ing `op_worker_recv_message` in
worker threads if closeOnIdle specified) and uses
`web_worker.has_message_event_listener` check in the opposite way as
#22944. (Now we continue the worker when `has_message_event_listener` is
true instead of stopping it when `has_message_event_listener` is false.

closes #23061
closes #26154
This commit is contained in:
Yoshiya Hinosawa 2024-12-19 17:39:20 +09:00 committed by GitHub
parent 55d345baed
commit 350d9dce41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 49 additions and 38 deletions

View file

@ -170,12 +170,14 @@ function postMessage(message, transferOrOptions = { __proto__: null }) {
let isClosing = false;
let globalDispatchEvent;
let closeOnIdle;
function hasMessageEventListener() {
// the function name is kind of a misnomer, but we want to behave
// as if we have message event listeners if a node message port is explicitly
// refed (and the inverse as well)
return event.listenerCount(globalThis, "message") > 0 ||
return (event.listenerCount(globalThis, "message") > 0 &&
!globalThis[messagePort.unrefParentPort]) ||
messagePort.refedMessagePortsCount > 0;
}
@ -188,7 +190,10 @@ async function pollForMessages() {
}
while (!isClosing) {
const recvMessage = op_worker_recv_message();
if (globalThis[messagePort.unrefPollForMessages] === true) {
// In a Node.js worker, unref() the op promise to prevent it from
// keeping the event loop alive. This avoids the need to explicitly
// call self.close() or worker.terminate().
if (closeOnIdle) {
core.unrefOpPromise(recvMessage);
}
const data = await recvMessage;
@ -915,6 +920,7 @@ function bootstrapWorkerRuntime(
6: argv0,
7: nodeDebug,
13: otelConfig,
14: closeOnIdle_,
} = runtimeOptions;
performance.setTimeOrigin();
@ -967,6 +973,7 @@ function bootstrapWorkerRuntime(
globalThis.pollForMessages = pollForMessages;
globalThis.hasMessageEventListener = hasMessageEventListener;
closeOnIdle = closeOnIdle_;
for (let i = 0; i <= unstableFeatures.length; i++) {
const id = unstableFeatures[i];