Stop throwing for unsupported options in `Worker`'s `execArgv` and `env.NODE_OPTIONS`.
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- JavaScript
- Star
- 122k
- Fork
- 37.3k
- Merge trung bình
- 4 ngày 2 giờ
- Pull request đã merge (30 ngày)
- 283
Mô tả
Version
v17.2.0
Platform
No response
Subsystem
worker_threads
What steps will reproduce the bug?
Consider this test.js file:
const { isMainThread, Worker } = require("worker_threads");
if (isMainThread) {
new Worker(__filename, {
// execArgv: process.execArgv
});
} else {
console.log("Hello from the worker!", process.execArgv);
}
NOTE:
--experimental-json-modulesand--titleare just examples
Run these two commands:
node --experimental-json-modules test.js
node --experimental-json-modules --title foo test.js
They will log
Hello from the worker! [ '--experimental-json-modules' ]
Hello from the worker! [ '--experimental-json-modules', '--title', 'foo' ]
Now, uncomment the execArgv: process.execArgv line and run the two commands again. The first command will still log
Hello from the worker! [ '--experimental-json-modules' ]
however, the second one throws:
Error [ERR_WORKER_INVALID_EXEC_ARGV]: Initiated Worker with invalid execArgv flags: --title
at new NodeError (node:internal/errors:371:5)
at new Worker (node:internal/worker:191:13)
at Object.<anonymous> (/home/nicolo/Documenti/dev/babel/babel/test.js:4:3)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47 {
code: 'ERR_WORKER_INVALID_EXEC_ARGV'
}
This mans that the default behavior of the Worker execArgv option is not to inherit execArgv from the parent thread (contrary to what the documentation says).
Why would you want to explicitly pass execArgv: process.execArgv anyway?
A few days ago I was trying to implement a require hook that internally uses a Worker, and in order to avoid registering it recursively in an infinite worker-spawn loop I tried to filter out the --require flag:
new Worker(workerFile, {
execArgv: process.execArgv.filter((val, i, argv) => val === "--requrie" || argv[i-1] === "--requrie"),
});
this seemed to work, until it crashed in a test that was using the --expose_gc option.
Today, I found the exact same problem in jest-worker (a Jest subpackage that is often also used outside of Jest): https://github.com/facebook/jest/pull/12103 was opened because jest-worker didn't work when running Node.js with --max_old_space_size.
Since Node.js doesn't provide the list of flags supported by workers progrmmatically (and I didn't find it in the docs either 😅) there is no way to filter the execArgv used by a worker.
What is the current behavior?
I initially expected the real default behavior to be something like execArgv: process.execArgv.filter(isSupportedByWorker), but it looks like it's not either. Consider for example the --expose_gc (which is disallowed in workers) option with this example:
const { isMainThread, Worker } = require("worker_threads");
if (isMainThread) {
new Worker(__filename);
} else {
console.log("Hello from the worker!", process.execArgv, globalThis.gc);
}
If you run node --expose_gc test.js, it will log
Hello from the worker! [ '--expose_gc' ] [Function: gc]
You can see that the gc function is present. This means that the disallowed flags are not ignored (and not even "ignored but still used to populate the process.execArgv array): they are used and affect the runtime behavior.
How often does it reproduce? Is there a required condition?
Only for the options marked as "unsupported" in workers.
What is the expected behavior?
I see four possible solutions:
- Just ignore the unsupported options
- Never throw, but warn when passing an unsupported option to a worker (potentially even if it's passed by default without an explicit
execArgv). - Only throw if the unsupported option is not also used as an
execArgvof the parent thread. - Always throw for unsupported options (so that
execArgv: process.execArgvbecomes the default behavior), and provide aWorker.filterExecArgvutility that removes disallowed options, and that I would have used likeWorker.filterExecArgv(process.execArgv).filter((val, i, argv) => val === "--requrie" || argv[i-1] === "--requrie")
If the current behavior is expected, then the docs should be updated to mention that the default value cannot be replicated by explicitly passing an execArgv option.
What do you see instead?
No response
Additional information
No response
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với các bản tái hiện worker_threads của test.js bằng cách sử dụng --experimental-json-modules, --title và --expose_gc, sau đó đọc tài liệu về Worker execArgv và entry point. Issue đưa ra một số lựa chọn hành vi không tương thích, vì vậy trước tiên hãy xác định cách xử lý dự kiến đối với execArgv không được hỗ trợ và env.NODE_OPTIONS; phần hoàn thành phải bao gồm hành vi tương ứng và độ bao phủ kiểm thử.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- javascript, node.js
- Lĩnh vực
- backend
- Loại issue
- Tính năng
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Cần làm rõ
- Mức phù hợp với người mới
- 35/100