Can't kill child process on Windows - node.js

The following will never exit
var child_process = require('child_process');
var ps = child_process.spawn('.\\node_modules\\.bin\\babel.cmd', ['input.js', '--out-file', 'output.js', '--watch']);
ps.on('exit', function() {
console.log('exit');
});
ps.on('close', function() {
console.log('close');
});
setTimeout(function () {
ps.kill();
}, 2000);
What's going on here? also what is the correct thing to do here? The only way to make this process actually close is to kill the parent process. I suspect it's waiting for stdio to flush or something like that?
It does die if it is given an 'ignore' stdio configuration, but I need the streams.
var ps = child_process.spawn('.\\node_modules\\.bin\\babel.cmd', ['test.js', '--out-file', 'output.js', '--watch'], {
stdio: 'ignore'
});

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.

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');

One potential solution is to call ReadableStream.end or ReadableStream.destroy

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);

For me, my process was spawn of cmd.exe with the args:
/s /c start /B /I /belownormal ffmpeg.exe -hide_banner -i somevideo.mp4 -vn -ar 48000 -ac 2 -c:a pcm_s16le -f wav -
I tried most of the suggested answers, but what solved it was calling child.stdin.destroy();
child.stderr.destroy();
child.stdout.destroy();
This could be because I was explicitly using stdout to get data from the process..
I still call child.kill('SIGINT'); for good measure.
taskkill gave me 'pid not found'.
(node 12).

Related

How to kill Node Express child process?

Inside one Node/Express server, I started another Node/Express server as child process:
let appifi = child.spawn('node', [babel_path, www_path], {
cwd: appifi_path,
env: appifi_env,
})
This worked fine and appifi got a pid, say 2376.
When trying to stop the child process, appifi.kill() will kill the process with pid 2376, but there is a respawned server process running, usually with a pid equals to it's parent's pid plus 5 (I don't know if this is a strict rule).
My question is, how to kill them both in parent server? is it safe to process.kill(appifi.pid + 5)? or there are any better ways?
You can kill both (actually, ALL) node servers by killall -9 node

Nodejs Terminate Spawned Child Process

I started a child process for a jar file by
var exec = require('child_process').exec;
// Start child process
var child = exec("java -jar test.jar");
and I terminated the child process by using a kill function that I wrote given the pid of the child
killProcess(child.pid);
The function always work when the pid is correct, however, because nodejs created the child process inside a cmd.exe shown in the picture below,
and the child.pid is the pid for the cmd.exe not the actual java.exe
My problem is that, occasionally, the java.exe will get too large and jump out of the cmd.exe and become an independent process, and I can't terminate it even when I stop the server. And because I don't have the pid of the java.exe I can't terminate it with my function.
What other ways can I terminate the process without doing it manually, or get the pid of the java.exe and not the cmd.exe?
It turns out, the problem is with the way how I create the child process.
Creating child process with exec has a size limit, thus, change it from exec to spawn solves the problem.
// Spawn the external jar file as a child process and listen print the output
var spawn = require('child_process').spawn;
// Start child process
var child = spawn('java', ['-jar', file_name]);

Run node as background process from script running as child process

I'm running a node server on port 5100. It executes a shell script as child process which in turn starts another node server.
var execFile = require('child_process').execFile;
execFile("./testscript", args, {cwd: cwd}, function (error, stdout, stderr) {
console.log("error.." + error);
console.log("stdout.." + stdout);
console.log("stderr.." + stderr);
})
In script i'm running a node process by nohup as :
nohup node server.js PORT=5200 2>/dev/null 1>/dev/null &
Now node#5200 has parentid of testscript which in turn has parentid of node#5100.
When i kill PID of node#5100 everything stops.
I want node#5200 to still run when testscript and node#5100 have exited.
You need to set the detached option when you create the child process. This is sort of like nohup. See the documentation here: http://nodejs.org/api/child_process.html#child_process_options_detached
What this does is to make the child process the leader of a new "process group," so when the parent process group dies, the child can continue running.
Edit: the documentation says:
When using the detached option to start a long-running process, the process will not stay running in the background unless it is provided with a stdio configuration that is not connected to the parent. If the parent's stdio is inherited, the child will remain attached to the controlling terminal.
So you must write code like this:
var child = spawn(cmd, args, {detached: true, stdio: ['ignore', 'ignore', 'ignore']});
child.unref();
Or you can use their example to have stdout redirect to a file, etc.
When i spawned a process from a file that ran once, my child process had perfect behavior as parent file exited normally.
Issue was raised as i was spawning process by a server file that was killed by Ctrl+c so it gave an error code on exit and as a result whole process group got SIGTERM which lead to killing of child process.
To successfully implement spawning i used double spawn i.e spawned a child process from my server file that further spawned child_process that ran my other node server. So i was able to avoid SIGTERM to reach grandchild and fulfill my requirement.

Why can I not kill my child process in nodejs on windows?

exec = require('child_process').exec;
child = exec('node child.js');
child.stdout.pipe(process.stdout);
child.kill('SIGKILL');
function wait() {
setTimeout(wait, 1000);
child.kill('SIGKILL');
}
wait();
The above code does not work. The child starts and will continue to write output indefinitely. I can not figure out how to kill this child process. I am running node v0.11.9 in Windows 7. I know that Windows does not use POSIX signals but sending it 'WM_QUIT' results in an exception. Is my best solution to setup an event protocol on stdin?
This still doesn't work for me with the current accepted answer. A work around on windows you can use is to call upon the windows taskkill program to kill the child process for you. Not quite as nice but it works. When you spawn the child you get a ProcessID (pid) stored in the child object returned when spawning, you can use with taskkill to kill the process.
var spawn = require('child_process').spawn;
spawn("taskkill", ["/pid", child.pid, '/f', '/t']);
I had to use the following package to kill my child process:
https://www.npmjs.com/package/tree-kill
The regular .kill command wouldn't work for me either on a raspberry pi.
If you want to be able to kill child processes via SIGKILL, use spawn instead, as spawn will create a child process (instead of a new shell like exec:
var exec = require('child_process').spawn;
Alternatively, you could pass the timeout parameter to exec, which will kill the process after that many milliseconds.
child = exec('node child.js', { timeout: 1000 });
Just an update
Now this code works (tested with Node.js 8.9.3 and Windows 10):
spawn = require('child_process').spawn;
child = spawn('node', ['child.js']);
setTimeout(function() {
child.kill();
}, 5000
);
check this code it worked for me.
var killer = require('child_process');
killer=exec('taskkill /F /pid '+child.pid);
Here killer is a variable and child is your child process.
when you create a child process it has many attributes associated with it and pid is one of them.
for more details on child process attributes and function check this node.js child process.
This program is to kill child process in windows environment.

Detached child process exits on script exit in node.js

I've followed the instructions in the api docs as far as I can tell. I spawn the process, using the options detached:true, stdio:['ignore','ignore','ignore'], I call unref on the ChildProcess. The ChildProcess has a pid, so I think it was successfully started. I'm trying to start a yeti server from within a grunt task. This code is within an async call, so next proceeds and eventually finishes the task. I use which to getcmd, and its the correct path to the yeti script in /usr/local/bin on Mac OSX 10.9. Port is also defined to an empty port. If I run the same command on the command line it works just fine. After the grunt exits I call ps aux | grep node and ps aux and grep for the logged pid and there is nothing running. Here is the code:
yeti = spawn("" + cmd + " --server --port " + port, [], {
detached: true,
stdio: ['ignore', 'ignore', 'ignore']
});
yeti.unref();
next("Yeti server is running. pid: " + yeti.pid);
Try this:
spawn(cmd, ["--server", "--port", port], {
detached: true,
stdio: ['ignore', 'ignore', 'ignore']
});
I've not seen a single example of spawn where everything was passed as the first argument. I've always seen it used with the first argument being only the command name (i.e. the executable name, or path to executable) and the second argument being an array of strings.
The fact that you were seeing a pid is not indicative of much because on Unix-type systems, the spawn will fork and then exec. The fork can be successful so you see a new pid but the exec fails because the executable's name makes no sense to the OS.
If you found this while investigating why your process exits when you kill the parent, though it's detached, and you're using PM2 :
https://github.com/Unitech/pm2/issues/1036
pm2 uses kill process tree. This kills the entire process tree. Running cli commands with --no-treekill will solve this.
related also: https://github.com/Unitech/PM2/issues/1564

Resources