-
-
Notifications
You must be signed in to change notification settings - Fork 33.5k
Description
Version
v20.0.0
Platform
Linux 5.19.0-38-generic #39~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 17 21:16:15 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
Subsystem
loaders
What steps will reproduce the bug?
Use childProcess.fork
within a loader, for example in the following loader:
// loader.mjs
import childProcess from "node:child_process";
const cp = childProcess.fork("./worker.mjs");
// worker.mjs
// Nothing needs to be in here for the behaviour to occur
// test.mjs
import readline from "node:readline";
function input(prompt = "") {
return new Promise((resolve) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question(prompt, (answer) => {
resolve(answer);
rl.close();
});
});
}
// This is included so we can control when the process ends
await input(`[Continue] `);
And run node --loader ./loader.mjs ./test.mjs
.
How often does it reproduce? Is there a required condition?
This happens consistently.
What is the expected behavior? Why is that the expected behavior?
The short answer is I'm not sure what should be done here. But it seems problematic that libraries (such as typescript
) that uses childProcess.fork
cannot be used within a loader without endless recursion of processes.
Perhaps the solution is simply not to carry over loaders onto child processes that are forked within loaders.
What do you see instead?
Loaders get continually created spamming the console with:
Loaded loader
(node:414589) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Loaded loader
(node:414589) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Loaded loader
(node:414589) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
while also rapidly growing memory usage from the endless chain of processes.
Additional information
I noticed this because ts-node
rapidly memory leaks in Node 20. I experimented it a bit and found that TypeScript is calling childProcess.fork
which causes this error. i.e. A minimal loader that exhibits this behaviour would just be:
// loader.mjs
import ts from "typescript";
// Haven't even written any hooks yet
Using this loader with node --loader ./loader.mjs ./test.mjs
will rapidly consume all memory on the machine until the OS kills the process (if not terminated sooner).