Skip to content

Commit 81e363a

Browse files
legendecastargos
authored andcommitted
worker: add argv constructor option
A convenience option to populate `process.argv` in worker threads. PR-URL: #30559Fixes: #30531 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Denys Otrishko <shishugi@gmail.com>
1 parent 2cc0482 commit 81e363a

4 files changed

Lines changed: 81 additions & 3 deletions

File tree

‎doc/api/worker_threads.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ changes:
510510
- version: REPLACEME
511511
pr-url: https://github.com/nodejs/node/pull/26628
512512
description: The `resourceLimits` option was introduced.
513+
- version: REPLACEME
514+
pr-url: https://github.com/nodejs/node/pull/30559
515+
description: The `argv` option was introduced.
513516
-->
514517

515518
*`filename` {string} The path to the Worker’s main script. Must be
@@ -518,6 +521,10 @@ changes:
518521
If `options.eval` is `true`, this is a string containing JavaScript code
519522
rather than a path.
520523
*`options` {Object}
524+
*`argv` {any[]} List of arguments which would be stringified and appended to
525+
`process.argv` in the worker. This is mostly similar to the `workerData`
526+
but the values will be available on the global `process.argv` as if they
527+
were passed as CLI options to the script.
521528
*`env` {Object} If set, specifies the initial value of `process.env` inside
522529
the Worker thread. As a special value, [`worker.SHARE_ENV`][] may be used
523530
to specify that the parent thread and the child thread should share their

‎lib/internal/main/worker_thread.js‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ if (process.env.NODE_CHANNEL_FD) {
9292
port.on('message',(message)=>{
9393
if(message.type===LOAD_SCRIPT){
9494
const{
95+
argv,
9596
cwdCounter,
9697
filename,
9798
doEval,
@@ -115,6 +116,9 @@ port.on('message', (message) => {
115116
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
116117
loadPreloadModules();
117118
initializeFrozenIntrinsics();
119+
if(argv!==undefined){
120+
process.argv=process.argv.concat(argv);
121+
}
118122
publicWorker.parentPort=publicPort;
119123
publicWorker.workerData=workerData;
120124

@@ -138,12 +142,22 @@ port.on('message', (message) => {
138142
port.postMessage({type: UP_AND_RUNNING});
139143
if(doEval){
140144
const{ evalScript }=require('internal/process/execution');
141-
evalScript('[worker eval]',filename);
145+
constname='[worker eval]';
146+
// This is necessary for CJS module compilation.
147+
// TODO: pass this with something really internal.
148+
ObjectDefineProperty(process,'_eval',{
149+
configurable: true,
150+
enumerable: true,
151+
value: filename,
152+
});
153+
process.argv.splice(1,0,name);
154+
evalScript(name,filename);
142155
}else{
143156
// script filename
144157
// runMain here might be monkey-patched by users in --require.
145158
// XXX: the monkey-patchability here should probably be deprecated.
146-
CJSLoader.Module.runMain(process.argv[1]=filename);
159+
process.argv.splice(1,0,filename);
160+
CJSLoader.Module.runMain(filename);
147161
}
148162
}elseif(message.type===STDIO_PAYLOAD){
149163
const{ stream, chunk, encoding }=message;

‎lib/internal/worker.js‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,16 @@ class Worker extends EventEmitter {
8686
validateString(filename,'filename');
8787
if(options.execArgv&&!ArrayIsArray(options.execArgv)){
8888
thrownewERR_INVALID_ARG_TYPE('options.execArgv',
89-
'array',
89+
'Array',
9090
options.execArgv);
9191
}
92+
letargv;
93+
if(options.argv){
94+
if(!ArrayIsArray(options.argv)){
95+
thrownewERR_INVALID_ARG_TYPE('options.argv','Array',options.argv);
96+
}
97+
argv=options.argv.map(String);
98+
}
9299
if(!options.eval){
93100
if(!path.isAbsolute(filename)&&!/^\.\.?[\\/]/.test(filename)){
94101
thrownewERR_WORKER_PATH(filename);
@@ -158,6 +165,7 @@ class Worker extends EventEmitter {
158165
this[kPublicPort].on('message',(message)=>this.emit('message',message));
159166
setupPortReferencing(this[kPublicPort],this,'message');
160167
this[kPort].postMessage({
168+
argv,
161169
type: messageTypes.LOAD_SCRIPT,
162170
filename,
163171
doEval: !!options.eval,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
constassert=require('assert');
4+
const{ Worker, isMainThread, workerData }=require('worker_threads');
5+
6+
if(isMainThread){
7+
assert.throws(()=>{
8+
newWorker(__filename,{argv: 'foo'});
9+
},{
10+
code: 'ERR_INVALID_ARG_TYPE'
11+
});
12+
13+
[
14+
newWorker(__filename,{
15+
argv: [null,'foo',123,Symbol('bar')],
16+
// Asserts only if the worker is started by the test.
17+
workerData: 'assert-argv'
18+
}),
19+
newWorker(`
20+
const assert = require('assert');
21+
assert.deepStrictEqual(
22+
process.argv,
23+
[process.execPath, '[worker eval]']
24+
);
25+
`,{
26+
eval: true
27+
}),
28+
newWorker(`
29+
const assert = require('assert');
30+
assert.deepStrictEqual(
31+
process.argv,
32+
[process.execPath, '[worker eval]', 'null', 'foo', '123',
33+
String(Symbol('bar'))]
34+
);
35+
`,{
36+
argv: [null,'foo',123,Symbol('bar')],
37+
eval: true
38+
})
39+
].forEach((worker)=>{
40+
worker.on('exit',common.mustCall((code)=>{
41+
assert.strictEqual(code,0);
42+
}));
43+
});
44+
}elseif(workerData==='assert-argv'){
45+
assert.deepStrictEqual(
46+
process.argv,
47+
[process.execPath,__filename,'null','foo','123',String(Symbol('bar'))]
48+
);
49+
}

0 commit comments

Comments
 (0)