Killing a child process from within itself in Node.JS - node.js

Is there a way to kill make a child process "suicide"? I tried with process.exit(1) but apparently it kills the whole application I'm running. I just want to kill the child process (like when we call process.kill() from the "father" of the child process). Also calling process.kill() within the child process kills the whole application.
Any idea?

process is always a reference to the main process. But you can simply use this:
var spawn = require( "child_process" ).spawn;
// example child process
var grep = spawn( "grep", [ "ssh"] );
grep.on( "exit", function (code, signal) {
console.log( "child process terminated due to receipt of signal "+signal);
});
grep.kill( "SIGHUP" );
I guess it depends on how you use child processes. But if you don't have a reference to the child process, then there is not much you can do.
WARNING: Killing child processes is almost never a good idea. You should send a message to the child processes and handle it in that process.

Related

Node.js - process.exit() vs childProcess.kill()

I have a node application that runs long running tasks so whenever a task runs a child process is forked to run the task. The code creates a fork for the task to be run and sends a message to the child process to start.
Originally, when the task was complete, I was sending a message back to the parent process and the parent process would call .kill() on the child process. I noticed in my activity monitor that the node processes weren't being removed. All the child processes were hanging around. So, instead of sending a message to the parent and calling .kill(), I called process.exit() in the child process code once the task was complete.
The second approach seems to work fine and I see the node processes being removed from the activity monitor but I'm wondering if there is a downside to this approach that I don't know about. Is one method better than the other? What's the difference between the 2 methods?
My code looks like this for the messaging approach.
//Parent process
const forked = fork('./app/jobs/onlineConcurrency.js');
forked.send({clientId: clientData.clientId,
schoolYear: schoolYear
});
forked.on("message", (msg) => {
console.log("message", msg);
forked.kill();
});
//child Process
process.on('message', (data) => {
console.log("Message recieved");
onlineConcurrencyJob(data.clientId, data.schoolYear, function() {
console.log("Killing process");
process.send("done");
});
})
The code looks like this for the child process when just exiting
//child Process
process.on('message', (data) => {
console.log("Message received");
onlineConcurrencyJob(data.clientId, data.schoolYear, function() {
console.log("Killing process");
process.exit();
});
})
kill sends a signal to the child process. Without an argument, it sends a SIGTERM (where TERM is short for "termination"), which typically, as the name suggests, terminates the process.
However, sending a signal like that is a forced method of stopping a process. If the process is performing tasks like writing to a file, and it receives a termination signal, it might cause file corruption because the process doesn't get a chance to write all data to the file, and close it (there are mitigations for this, like installing a signal handler that can be used to "catch" signals and ignore them, or finish all tasks before exiting, but this requires explicit code to be added to the child process).
Whereas with process.exit(), the process exits itself. And typically, it does so at a point where it knows that there are no more pending tasks, so it can exit cleanly. This is generally speaking the best way to stop a (child) process.
As for why the processes aren't being removed, I'm not sure. It could be that the parent process isn't cleaning up the resources for the child processes, but I would expect that to happen automatically (I don't even think you can perform so-called "child reaping" explicitly in Node.js).
Calling process.exit(0) is the best mechanism, though there are cases where you might want to .kill from the parent (eg. A distributed search where one node returning means all nodes can stop).
.kill is probably failing due to some handling of the signal it is getting. Try .kill('SIGTERM'), or even 'SIGKILL'.
Also note that subprocesses which aren't killed when the parent process exits will be moved to the grandparent process. See here for more info and a proposed workaround: https://github.com/nodejs/node/issues/13538
In summary, this is default Unix behavior, and the workaround is to process.on("exit", () => child.kill())

node.js, process.kill() and process.exit(0), which one can kill process?

I read node.js docs. It says:
Even though the name of this function is process.kill(), it is really just a signal sender, as the kill system call. The signal sent may do something other than killing the target process.
console.log('current process id: ', process.pid);
process.on('SIGHUP', function() {
console.log('Got SIGHUP signal');
});
setTimeout(() => {
console.log('Exiting...');
process.exit(0); //kill process
console.log('Process id that has exited: ', process.pid); //does not output
}, 1000);
process.kill(process.pid, 'SIGHUP'); //does not kill process
console.log('Id of the process exiting: ', process.pid); //so this output normally
output:
current process id: 64520
Id of the process exiting: 64520
Got SIGHUP signal
Exiting...
It seems process.exit(0) is the one which kills node.js process.
It all depends on the situation that you're in. Like Gospal Joshi said process.exit([code]) is useful to end the process very quickly. But in other cases you may want to pass a signal to that process before shutdown for cleanup/graceful shutdown. For example if you are listening to signal events such as:
process.on('SIGINT', () => {
//do something
}
it allows you to run cleanup or gracefully shutdown the process vs exiting instantly without doing anything.
Also, note that Node.js establishes signal handlers for SIGINT and SIGTERM and Node.js processes will not terminate immediately due to receipt of those signals. Rather, Node.js will perform a sequence of cleanup actions and then will re-raise the handled signal - Node Documentation
process.kill(pid, [ code ]) shines on concurrent applications with multiple processes (since you can just plug in the pid of the process you wish to kill and it does it).
process.exit() is sufficient and most common if you dont have a usecase that requires killing any other process than the main node process.
Personally, I recommend you to use process.exit() unless you really have to kill another process (pid different than process.pid)
Use process.exit(), It ends the process with the specified code. Calling process.exit() will force the process to exit as quickly as possible even if there are still asynchronous operations pending
Syntax:
process.exit([code])
Links:
Exit codes
Exit() Documentation

NodeJS child processes are terminated on SIGINT

Im creating NodeJS application, that creates quite a few child processes. They are started by both spawn and exec (based on lib implementation). Some examples may be GraphicsMagick (gm) for image manipulation or Tesseract (node-tesseract) for OCR. Now I would like to gracefully end my application so I created shutdown hook:
function exitHandler() {
killer.waitForShutdown().then(function(){
logger.logInfo("Exited successfully.");
process.exit();
}).catch(function(err) {
logger.logError(err, "Error during server shutdown.");
process.exit();
});
}
process.on('exit', exitHandler);
process.on('SIGINT', exitHandler);
process.on('SIGTERM', exitHandler);
Exit handling itself works fine, it is waiting well and so on, but there is a catch. All "native" (gm, tesseract, ...) processes that run at that time are also killed. Exception messages only consists of "Command failed" and then content of command which failed e.g.
"Command failed: /bin/sh -c tesseract tempfiles/W1KwFSdz7MKdJQQnUifQFKdfTRDvBF4VkdJgEvxZGITng7JZWcyPYw6imrw8JFVv/ocr_0.png /tmp/node-tesseract-49073e55-0ef6-482d-8e73-1d70161ce91a -l eng -psm 3\nTesseract Open Source OCR Engine v3.03 with Leptonica"
So at least for me, they do not tell anything useful. I'm also queuing process execution, so PC don't get overloaded by 50 processes at one time. When running processes are killed by SIGINT, new processes that were queued are started just fine and finishes successfully. I have problem only with those few running at the time of receiving SIGINT. This behavior is same on Linux (Debian 8) and Windows (W10). From what I read here, people usually have opposite problem (to kill child processes). I tried to search if stdin gets somehow piped into child processes but I can't find it. So is this how its supposed to work? Is there any trick to prevent this behavior?
The reason this happens is because, by default, the detached option is set to false. If detached is false, the signals will also be sent to the child processes, regardless of whether you setup an event listener.
To stop this happening, you need to change your spawn calls to use the third argument in order to specify detached; for example:
spawn('ls', ['-l'], { detached: true })
From the Node documentation:
On Windows, setting options.detached to true makes it possible for the
child process to continue running after the parent exits. The child
will have its own console window. Once enabled for a child process, it
cannot be disabled.
On non-Windows platforms, if options.detached is set to true, the
child process will be made the leader of a new process group and
session. Note that child processes may continue running after the
parent exits regardless of whether they are detached or not. See
setsid(2) for more information.

Killing CPU bound child process

I have a child process spawned using child_process.fork and would like to terminate it. The problem is that the child process does some lengthy CPU bound calculation and I don't have control over it. That is, the CPU bound code fragment cannot be restructured to make use of process.nextTick or polling.
A very simplified example:
parent.js
var cp = require('child_process');
var child = cp.fork('child.js');
child.js
...
while(true){} // lengthy computation which I cannot modify
...
Is it possible to terminate it? Preferably in a way that allows catching the exit event in the child in order to do some cleanups?
Sending SIGTERM/SIGKILL/etc using child.kill() doesn't
seem to work on Windows. I assume even if it works on other OSes it wouldn't kill the process anyway due to child not being able to process events while doing the computation.
I've done this the messy way by using the PID of the process and killing it at the OS level.
Not sure how to do it in windows, but in Linux/mac I've done:
var cp = require('child_process'),
badJob = cp.fork('badFile.js');
cp.execSync('kill -9 ' + badJob.pid);
The signal 9 is caught at the Kernel level, so the condition of the process is irrelevant.
Edit: In Windows you can use taskkill instead of kill. ex:
cp.execSync('taskkill /f ' + badJob.pid);

Start new process as system process

Is it possible to start a process out of node, which is not a child process from the node instance but a system process?
If i use child_process, new processes are included in the father process. The problem is, that all other processes will be killed, if the father process is canceled. I want to run the new processes instead the father process is killed.
Give child.unref() a try. According to the node.js documentation:
If the detached option is set, the child process will be made the leader of a new process group. This makes it possible for the child to continue running after the parent exits.
By default, the parent will wait for the detached child to exit. To prevent the parent from waiting for a given child, use the child.unref() method, and the parent's event loop will not include the child in its reference count.
Emphasis mine. So knowing that, you can also pass in true to the detached option in the options hash when forking:
var child = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});

Resources