Closed
Description
Version
v18.9.0
Platform
Linux Mint 20.1
Subsystem
child_process
What steps will reproduce the bug?
- Create a child process with an AbortSignal attached.
- Abort the child process via AbortSignal before the child process
exit
event - This will trigger the child process's
error
event.
The following code will generate the error for spawn
, execFile
, and exec
const { spawn, exec, execFile } = require("child_process");
const tests = [
{ commandName: "spawn", command: spawn },
{ commandName: "execFile", command: execFile },
{ commandName: "exec", command: exec }
];
(async () => {
for ( let { commandName, command } of tests ) {
const abortController = new AbortController();
await new Promise( resolve => {
// I used 'ls' but the command does not seem to effect the result
const child = command( "ls", { signal: abortController.signal } )
.on( "error", ( err ) =>
console.log({ event: `${commandName}.error`, killed: child.killed, err }) )
.on( "exit", ( code, signal ) => {
console.log({ event: `${commandName}.exit`, code, signal, killed: child.killed });
} )
.on( "close", ( code, signal ) => {
console.log({ event: `${commandName}.close`, code, signal, killed: child.killed });
resolve();
} )
.on( "spawn", () => {
console.log({ event: `${commandName}.spawn`, killed: child.killed });
// child.kill( "SIGTERM" ); // child will NOT cause an 'error' event
abortController.abort(); // child will cause an 'error' event
} );
} );
}
})();
How often does it reproduce? Is there a required condition?
This occurs every time, a child process is aborted via AbortSignal and it has not performed it's exit event.
What is the expected behavior?
{ event: 'spawn.spawn', killed: false }
{ event: 'spawn.exit', code: null, signal: 'SIGTERM', killed: true }
{ event: 'spawn.close', code: null, signal: 'SIGTERM', killed: true }
...
Repeated for execFile and exec
What do you see instead?
{ event: 'spawn.spawn', killed: false }
{
event: 'spawn.error',
killed: true,
err: AbortError: The operation was aborted
at abortChildProcess (node:child_process:706:27)
at AbortSignal.onAbortListener (node:child_process:776:7)
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:731:20)
at AbortSignal.dispatchEvent (node:internal/event_target:673:26)
at abortSignal (node:internal/abort_controller:292:10)
at AbortController.abort (node:internal/abort_controller:322:5)
at ChildProcess.<anonymous> (/index.js:30:29)
at ChildProcess.emit (node:events:513:28)
at onSpawnNT (node:internal/child_process:481:8)
at process.processTicksAndRejections (node:internal/process/task_queues:81:21) {
code: 'ABORT_ERR'
}
}
{ event: 'spawn.exit', code: 0, signal: null, killed: true }
{ event: 'spawn.close', code: 0, signal: null, killed: true }
...
Repeated for execFile and exec
Additional information
According to the documentation a child process error
event occurs only on:
- The process could not be spawned, or
- The process could not be killed, or
- Sending a message to the child process failed.
None of these conditions are true when the process is aborted via AbortSignal. If the child process is terminated via a child.kill( "SIGTERM" )
it does not trigger the error
event.
I am assuming that AbortSignal.abort()
is suppose to act like child.kill( "SIGTERM" )
and not that the documentation is out-of-date.