workers: fix spawning from preload scripts

Fix spawning nested worker threads from preload scripts and
warn about doing so.

Signed-off-by: James M Snell <jasnell@gmail.com>
Fixes: https://github.com/nodejs/node/issues/36531

PR-URL: https://github.com/nodejs/node/pull/37481
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
James M Snell 2021-02-22 12:58:47 -08:00
parent da217d0773
commit 360e8c842a
No known key found for this signature in database
GPG Key ID: 7341B15C070877AC
4 changed files with 35 additions and 4 deletions

View File

@ -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

View File

@ -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) {
ArrayPrototypePushApply(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);

9
test/fixtures/worker-preload.js vendored Normal file
View File

@ -0,0 +1,9 @@
const {
Worker,
workerData,
threadId
} = require('worker_threads');
if (threadId < 2) {
new Worker('1 + 1', { eval: true });
}

View File

@ -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());