worker: provide process.execArgv
Provide `process.execArgv`. If an `execArgv` option is passed to the `Worker` constructor, that option is used as its value; if not, the parent’s `process.execArgv` is inherited (since that also goes for the actual options in that case). PR-URL: https://github.com/nodejs/node/pull/26267 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
b8018f407b
commit
f65b4afaea
@ -428,7 +428,9 @@ if (isMainThread) {
|
|||||||
not automatically be piped through to `process.stderr` in the parent.
|
not automatically be piped through to `process.stderr` in the parent.
|
||||||
* `execArgv` {string[]} List of node CLI options passed to the worker.
|
* `execArgv` {string[]} List of node CLI options passed to the worker.
|
||||||
V8 options (such as `--max-old-space-size`) and options that affect the
|
V8 options (such as `--max-old-space-size`) and options that affect the
|
||||||
process (such as `--title`) are not supported.
|
process (such as `--title`) are not supported. If set, this will be provided
|
||||||
|
as [`process.execArgv`][] inside the worker. By default, options will be
|
||||||
|
inherited from the parent thread.
|
||||||
|
|
||||||
### Event: 'error'
|
### Event: 'error'
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
@ -582,6 +584,7 @@ active handle in the event system. If the worker is already `unref()`ed calling
|
|||||||
[`process.abort()`]: process.html#process_process_abort
|
[`process.abort()`]: process.html#process_process_abort
|
||||||
[`process.chdir()`]: process.html#process_process_chdir_directory
|
[`process.chdir()`]: process.html#process_process_chdir_directory
|
||||||
[`process.env`]: process.html#process_process_env
|
[`process.env`]: process.html#process_process_env
|
||||||
|
[`process.execArgv`]: process.html#process_process_execargv
|
||||||
[`process.exit()`]: process.html#process_process_exit_code
|
[`process.exit()`]: process.html#process_process_exit_code
|
||||||
[`process.stderr`]: process.html#process_process_stderr
|
[`process.stderr`]: process.html#process_process_stderr
|
||||||
[`process.stdin`]: process.html#process_process_stdin
|
[`process.stdin`]: process.html#process_process_stdin
|
||||||
|
@ -605,6 +605,10 @@ inline std::shared_ptr<EnvironmentOptions> Environment::options() {
|
|||||||
return options_;
|
return options_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const std::vector<std::string>& Environment::exec_argv() {
|
||||||
|
return exec_argv_;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<HostPort> Environment::inspector_host_port() {
|
inline std::shared_ptr<HostPort> Environment::inspector_host_port() {
|
||||||
return inspector_host_port_;
|
return inspector_host_port_;
|
||||||
}
|
}
|
||||||
|
@ -386,6 +386,7 @@ MaybeLocal<Object> Environment::ProcessCliArgs(
|
|||||||
std::move(traced_value));
|
std::move(traced_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exec_argv_ = exec_args;
|
||||||
Local<Object> process_object =
|
Local<Object> process_object =
|
||||||
node::CreateProcessObject(this, args, exec_args)
|
node::CreateProcessObject(this, args, exec_args)
|
||||||
.FromMaybe(Local<Object>());
|
.FromMaybe(Local<Object>());
|
||||||
|
@ -676,6 +676,7 @@ class Environment {
|
|||||||
v8::MaybeLocal<v8::Object> ProcessCliArgs(
|
v8::MaybeLocal<v8::Object> ProcessCliArgs(
|
||||||
const std::vector<std::string>& args,
|
const std::vector<std::string>& args,
|
||||||
const std::vector<std::string>& exec_args);
|
const std::vector<std::string>& exec_args);
|
||||||
|
inline const std::vector<std::string>& exec_argv();
|
||||||
|
|
||||||
typedef void (*HandleCleanupCb)(Environment* env,
|
typedef void (*HandleCleanupCb)(Environment* env,
|
||||||
uv_handle_t* handle,
|
uv_handle_t* handle,
|
||||||
@ -1060,6 +1061,7 @@ class Environment {
|
|||||||
// the inspector_host_port_->port() will be the actual port being
|
// the inspector_host_port_->port() will be the actual port being
|
||||||
// used.
|
// used.
|
||||||
std::shared_ptr<HostPort> inspector_host_port_;
|
std::shared_ptr<HostPort> inspector_host_port_;
|
||||||
|
std::vector<std::string> exec_argv_;
|
||||||
|
|
||||||
uint32_t module_id_counter_ = 0;
|
uint32_t module_id_counter_ = 0;
|
||||||
uint32_t script_id_counter_ = 0;
|
uint32_t script_id_counter_ = 0;
|
||||||
|
@ -101,10 +101,12 @@ void AsyncRequest::MemoryInfo(MemoryTracker* tracker) const {
|
|||||||
Worker::Worker(Environment* env,
|
Worker::Worker(Environment* env,
|
||||||
Local<Object> wrap,
|
Local<Object> wrap,
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
std::shared_ptr<PerIsolateOptions> per_isolate_opts)
|
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
|
||||||
|
std::vector<std::string>&& exec_argv)
|
||||||
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
|
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
|
||||||
url_(url),
|
url_(url),
|
||||||
per_isolate_opts_(per_isolate_opts),
|
per_isolate_opts_(per_isolate_opts),
|
||||||
|
exec_argv_(exec_argv),
|
||||||
platform_(env->isolate_data()->platform()),
|
platform_(env->isolate_data()->platform()),
|
||||||
profiler_idle_notifier_started_(env->profiler_idle_notifier_started()),
|
profiler_idle_notifier_started_(env->profiler_idle_notifier_started()),
|
||||||
thread_id_(Environment::AllocateThreadId()) {
|
thread_id_(Environment::AllocateThreadId()) {
|
||||||
@ -284,7 +286,7 @@ void Worker::Run() {
|
|||||||
|
|
||||||
env_->Start(profiler_idle_notifier_started_);
|
env_->Start(profiler_idle_notifier_started_);
|
||||||
env_->ProcessCliArgs(std::vector<std::string>{},
|
env_->ProcessCliArgs(std::vector<std::string>{},
|
||||||
std::vector<std::string>{});
|
std::move(exec_argv_));
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(this, "Created Environment for worker with id %llu", thread_id_);
|
Debug(this, "Created Environment for worker with id %llu", thread_id_);
|
||||||
@ -434,6 +436,9 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
std::string url;
|
std::string url;
|
||||||
std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
|
std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
|
||||||
|
|
||||||
|
std::vector<std::string> exec_argv_out;
|
||||||
|
bool has_explicit_exec_argv = false;
|
||||||
|
|
||||||
// Argument might be a string or URL
|
// Argument might be a string or URL
|
||||||
if (args.Length() > 0 && !args[0]->IsNullOrUndefined()) {
|
if (args.Length() > 0 && !args[0]->IsNullOrUndefined()) {
|
||||||
Utf8Value value(
|
Utf8Value value(
|
||||||
@ -445,6 +450,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
v8::Local<v8::Array> array = args[1].As<v8::Array>();
|
v8::Local<v8::Array> array = args[1].As<v8::Array>();
|
||||||
// The first argument is reserved for program name, but we don't need it
|
// The first argument is reserved for program name, but we don't need it
|
||||||
// in workers.
|
// in workers.
|
||||||
|
has_explicit_exec_argv = true;
|
||||||
std::vector<std::string> exec_argv = {""};
|
std::vector<std::string> exec_argv = {""};
|
||||||
uint32_t length = array->Length();
|
uint32_t length = array->Length();
|
||||||
for (uint32_t i = 0; i < length; i++) {
|
for (uint32_t i = 0; i < length; i++) {
|
||||||
@ -472,7 +478,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// options for the per isolate parser.
|
// options for the per isolate parser.
|
||||||
options_parser::PerIsolateOptionsParser::instance.Parse(
|
options_parser::PerIsolateOptionsParser::instance.Parse(
|
||||||
&exec_argv,
|
&exec_argv,
|
||||||
nullptr,
|
&exec_argv_out,
|
||||||
&invalid_args,
|
&invalid_args,
|
||||||
per_isolate_opts.get(),
|
per_isolate_opts.get(),
|
||||||
kDisallowedInEnvironment,
|
kDisallowedInEnvironment,
|
||||||
@ -492,7 +498,9 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new Worker(env, args.This(), url, per_isolate_opts);
|
if (!has_explicit_exec_argv)
|
||||||
|
exec_argv_out = env->exec_argv();
|
||||||
|
new Worker(env, args.This(), url, per_isolate_opts, std::move(exec_argv_out));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
|
void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
@ -38,7 +38,8 @@ class Worker : public AsyncWrap {
|
|||||||
Worker(Environment* env,
|
Worker(Environment* env,
|
||||||
v8::Local<v8::Object> wrap,
|
v8::Local<v8::Object> wrap,
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
std::shared_ptr<PerIsolateOptions> per_isolate_opts);
|
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
|
||||||
|
std::vector<std::string>&& exec_argv);
|
||||||
~Worker() override;
|
~Worker() override;
|
||||||
|
|
||||||
// Run the worker. This is only called from the worker thread.
|
// Run the worker. This is only called from the worker thread.
|
||||||
@ -74,6 +75,7 @@ class Worker : public AsyncWrap {
|
|||||||
const std::string url_;
|
const std::string url_;
|
||||||
|
|
||||||
std::shared_ptr<PerIsolateOptions> per_isolate_opts_;
|
std::shared_ptr<PerIsolateOptions> per_isolate_opts_;
|
||||||
|
std::vector<std::string> exec_argv_;
|
||||||
MultiIsolatePlatform* platform_;
|
MultiIsolatePlatform* platform_;
|
||||||
v8::Isolate* isolate_ = nullptr;
|
v8::Isolate* isolate_ = nullptr;
|
||||||
bool profiler_idle_notifier_started_;
|
bool profiler_idle_notifier_started_;
|
||||||
|
@ -20,26 +20,46 @@
|
|||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const spawn = require('child_process').spawn;
|
const spawn = require('child_process').spawn;
|
||||||
|
const { Worker, isMainThread } = require('worker_threads');
|
||||||
|
|
||||||
if (process.argv[2] === 'child') {
|
if (process.argv[2] === 'child' || !isMainThread) {
|
||||||
|
if (process.argv[3] === 'cp+worker')
|
||||||
|
new Worker(__filename);
|
||||||
|
else
|
||||||
process.stdout.write(JSON.stringify(process.execArgv));
|
process.stdout.write(JSON.stringify(process.execArgv));
|
||||||
} else {
|
} else {
|
||||||
for (const extra of [ [], [ '--' ] ]) {
|
for (const extra of [ [], [ '--' ] ]) {
|
||||||
const execArgv = ['--stack-size=256'];
|
for (const kind of [ 'cp', 'worker', 'cp+worker' ]) {
|
||||||
const args = [__filename, 'child', 'arg0'];
|
const execArgv = ['--pending-deprecation'];
|
||||||
const child = spawn(process.execPath, [...execArgv, ...extra, ...args]);
|
const args = [__filename, 'child', kind];
|
||||||
let out = '';
|
let child;
|
||||||
|
switch (kind) {
|
||||||
|
case 'cp':
|
||||||
|
child = spawn(process.execPath, [...execArgv, ...extra, ...args]);
|
||||||
|
break;
|
||||||
|
case 'worker':
|
||||||
|
child = new Worker(__filename, {
|
||||||
|
execArgv: [...execArgv, ...extra],
|
||||||
|
stdout: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'cp+worker':
|
||||||
|
child = spawn(process.execPath, [...execArgv, ...args]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let out = '';
|
||||||
child.stdout.setEncoding('utf8');
|
child.stdout.setEncoding('utf8');
|
||||||
child.stdout.on('data', function(chunk) {
|
child.stdout.on('data', (chunk) => {
|
||||||
out += chunk;
|
out += chunk;
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on('close', function() {
|
child.stdout.on('end', common.mustCall(() => {
|
||||||
assert.deepStrictEqual(JSON.parse(out), execArgv);
|
assert.deepStrictEqual(JSON.parse(out), execArgv);
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,13 @@ const assert = require('assert');
|
|||||||
// This test ensures that Workers have the ability to get
|
// This test ensures that Workers have the ability to get
|
||||||
// their own command line flags.
|
// their own command line flags.
|
||||||
|
|
||||||
const { Worker, isMainThread } = require('worker_threads');
|
const { Worker } = require('worker_threads');
|
||||||
const { StringDecoder } = require('string_decoder');
|
const { StringDecoder } = require('string_decoder');
|
||||||
const decoder = new StringDecoder('utf8');
|
const decoder = new StringDecoder('utf8');
|
||||||
|
|
||||||
if (isMainThread) {
|
// Do not use isMainThread so that this test itself can be run inside a Worker.
|
||||||
|
if (!process.env.HAS_STARTED_WORKER) {
|
||||||
|
process.env.HAS_STARTED_WORKER = 1;
|
||||||
const w = new Worker(__filename, { execArgv: ['--trace-warnings'] });
|
const w = new Worker(__filename, { execArgv: ['--trace-warnings'] });
|
||||||
w.stderr.on('data', common.mustCall((chunk) => {
|
w.stderr.on('data', common.mustCall((chunk) => {
|
||||||
const error = decoder.write(chunk);
|
const error = decoder.write(chunk);
|
||||||
@ -19,4 +21,5 @@ if (isMainThread) {
|
|||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
process.emitWarning('some warning');
|
process.emitWarning('some warning');
|
||||||
|
assert.deepStrictEqual(process.execArgv, ['--trace-warnings']);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user