The following will never exit
var child_process = require(\'child_process\');
var ps = child_process.spawn(\'.\\\\node_modules\\\\.bin\\\\babel.cmd\', [\'in
I have the same issue on Windows (Win 10 64x). I can't terminate a process of a spawned child process.
I start a service (custom HTTP server service.windows
) using child_process.spawn()
:
const { spawn } = require('child_process');
let cp = spawn('"C:\\Users\\user\\app\\service.windows"', [], { shell: true, });
cp.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
console.log('cp.connected', cp.connected);
console.log('process.pid', process.pid); // 6632 <<= main node.js PID
console.log('cp.pid', cp.pid); // 9424 <<= child PID
// All these are useless, they just kill `cp`
cp.kill('SIGINT'); // Doesn't terminate service.windows
cp.kill('SIGKILL'); // Doesn't terminate service.windows
cp.kill('SIGTERM'); // Doesn't terminate service.windows
});
And I want to terminate my HTTP server service (service.windows
). And it is not possible on Windows using cp.kill('ANY SIGNAL')
. Node.js kills its child process (cp
) but my HTTP server (service.windows
) still runs fine.
When I check it in other terminal, I see my server is running just fine:
$ netstat -ano | findstr :9090
TCP 0.0.0.0:9090 0.0.0.0:0 LISTENING 1340
TCP [::]:9090 [::]:0 LISTENING 1340
I try manually kill my server by PID
but with T
flag, not F
. The difference:
T
terminate all child processes along with the parent process, commonly known as a tree kill.
F
process(es) be forcefully terminated.
$ taskkill -T -PID 1340
ERROR: The process with PID 1340 (child process of PID 9424) could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).
And it exactly says that my server 1340
is a child of that cp
- PID 9424
.
OK, I try to terminate that cp
using T
flag again. And boom, not possible. cp
is a child of my main node.js process.pid
6632:
$ taskkill -T -PID 9424
ERROR: The process with PID 1340 (child process of PID 9424) could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).
ERROR: The process with PID 9424 (child process of PID 6632) could not be terminated.
Reason: One or more child processes of this process were still running.
I can only kill it forcefully with F
flag:
$ taskkill -F -T -PID 9424
SUCCESS: The process with PID 1340 (child process of PID 9424) has been terminated.
SUCCESS: The process with PID 9424 (child process of PID 6632) has been terminated.
Most disappointing thing is that Node.js docs doesn't say jack ship about how to deal with this issue. They only say "yes, we know the issue exist and we just inform you about it".
The only option I see on Windows is to use taskkill -F -T -PID 9424
in spawned process:
exec('taskkill -F -T -PID 9424');
The most straight forward solution, don't spawn scripts instead spawn node directly.
For unix, the script is the npm executable. For windows however we need to resolve the name from the .cmd file.
if (path.extname(command).toLowerCase() == '.cmd') {
var content = '' + fs.readFileSync(command);
var link = (/node "%~dp0\\(.*?)"/.exec(content) || [])[1];
if (link) {
command = path.resolve(path.dirname(command), link);
}
}
var ps = child.spawn('node', [command].concat(args), options);
One potential solution is to call ReadableStream.end
or ReadableStream.destroy
You are spawning child process cmd.exe
by using babel.cmd
. This process then starts another grandchild process node
and runs babel script. When you do ps.kill()
it only kills the cmd.exe
but not the child processes created by it.
Although cmd.exe
is closed, the stdio stream of the parent process is still shared with the other processes in the tree. So the parent process is waiting for the stream to be closed. Using stdio: 'ignore'
will only stop sharing the stdio stream with other processes in the tree but those grandchild processes will still continue running.
Update:
After discussing with OP, I tested with all three stdio options: pipe
(default), inherit
, ignore
in iojs 3.3.0, Windows 7 (32bit). None of them kills the grandchild process.
With inherit
and ignore
, both parent process and child process(cmd.exe) are killed but the grand child process still floats around and doesn't belong to any process tree.
With pipe
, only the child process is terminated but both parent and grand child process continue running. The reason that parent process is not exiting is most likely because the stdio of parent node.exe is still shared with the other processes as mentioned in original answer.
child.unref()
doesn't have any effect on killing grand child process. It only removes the child process from parent's event loop so that the parent process can exit normally.
I could think of couple of solutions:
Invoke the babel.js
directly without that cmd script:
var ps = child_process.spawn('node', ['.\\node_modules\\babel\\bin\\babel.js', 'input.js', '--out-file', 'output.js', '--watch'])
Use windows taskkill
command with \T
flag to kill the process and all the child processes started by it:
os = require('os');
if(os.platform() === 'win32'){
child_process.exec('taskkill /pid ' + ps.pid + ' /T /F')
}else{
ps.kill();
}
There are some npm modules that can handle killing child processes in both Unix and Windows e.g. tree-kill. For windows it uses taskkill
or tasklist
.