From 671bbc76de2f2a4ccd93640cc45df95784d3340f Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 22 Feb 2021 12:58:47 -0800 Subject: [PATCH] worker_threads: fix spawning from preload scripts Fix spawning nested worker threads from preload scripts and warn about doing so. Signed-off-by: James M Snell Fixes: https://github.com/nodejs/node/issues/36531 --- doc/api/worker_threads.md | 11 +++++++++++ lib/internal/main/worker_thread.js | 9 +++++---- test/fixtures/worker-preload.js | 9 +++++++++ test/parallel/test-preload-worker.js | 10 ++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/worker-preload.js create mode 100644 test/parallel/test-preload-worker.js diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index f113bb2d967805..3f184d5ffe2f05 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -1127,6 +1127,17 @@ Calling `unref()` on a worker allows the thread to exit if this is the only active handle in the event system. If the worker is already `unref()`ed calling `unref()` again has no effect. +## Notes + +### Launching worker threads from preload scripts + +Take care when launching worker threads from preload scripts (scripts loaded +and run using the `-r` command line flag). Unless the `execArgv` option is +explicitly set, new Worker threads automatically inherit the command line flags +from the running process and will preload the same preload scripts as the main +thread. If the preload script unconditionally launches a worker thread, every +thread spawned will spawn another until the application crashes. + [Addons worker support]: addons.md#addons_worker_support [ECMAScript module loader]: esm.md#esm_data_imports [HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js index 36c5d4c5675413..99ce7f35d1d51c 100644 --- a/lib/internal/main/worker_thread.js +++ b/lib/internal/main/worker_thread.js @@ -121,10 +121,6 @@ port.on('message', (message) => { initializeCJSLoader(); initializeESMLoader(); - const CJSLoader = require('internal/modules/cjs/loader'); - assert(!CJSLoader.hasLoadedAnyUserCJSModule); - loadPreloadModules(); - initializeFrozenIntrinsics(); if (argv !== undefined) { process.argv = ArrayPrototypeConcat(process.argv, argv); } @@ -147,6 +143,11 @@ port.on('message', (message) => { }; workerIo.sharedCwdCounter = cwdCounter; + const CJSLoader = require('internal/modules/cjs/loader'); + assert(!CJSLoader.hasLoadedAnyUserCJSModule); + loadPreloadModules(); + initializeFrozenIntrinsics(); + if (!hasStdin) process.stdin.push(null); diff --git a/test/fixtures/worker-preload.js b/test/fixtures/worker-preload.js new file mode 100644 index 00000000000000..6e5c4a31d2f20e --- /dev/null +++ b/test/fixtures/worker-preload.js @@ -0,0 +1,9 @@ +const { + Worker, + workerData, + threadId +} = require('worker_threads'); + +if (threadId < 2) { + new Worker('1 + 1', { eval: true }); +} diff --git a/test/parallel/test-preload-worker.js b/test/parallel/test-preload-worker.js new file mode 100644 index 00000000000000..3e9134b470cf37 --- /dev/null +++ b/test/parallel/test-preload-worker.js @@ -0,0 +1,10 @@ +'use strict'; + +const common = require('../common'); +const fixtures = require('../common/fixtures'); +const worker = fixtures.path('worker-preload.js'); +const { exec } = require('child_process'); +const kNodeBinary = process.argv[0]; + + +exec(`"${kNodeBinary}" -r "${worker}" -pe "1+1"`, common.mustSucceed());