Detect when parent process exits - node.js

I will have a parent process that is used to handle webserver restarts. It will signal the child to stop listening for new requests, the child will signal the parent that it has stopped listening, then the parent will signal the new child that it can start listening. In this way, we can accomplish less than 100ms down time for a restart of that level (I have a zero-downtime grandchild restart also, but that is not always enough of a restart).
The service manager will kill the parent when it is time for shutdown. How can the child detect that the parent has ended?
The signals are sent using stdin and stdout of the child process. Perhaps I can detect the end of an stdin stream? I am hoping to avoid a polling interval. Also, I would like this to be a really quick detection if possible.

a simpler solution could be by registering for 'disconnect' in the child process
process.on('disconnect', function() {
console.log('parent exited')
process.exit();
});

This answer is just for providing an example of the node-ffi solution that entropo has proposed (above) (as mentioned it will work on linux):
this is the parent process, it is spawning the child and then exit after 5 seconds:
var spawn = require('child_process').spawn;
var node = spawn('node', [__dirname + '/child.js']);
setTimeout(function(){process.exit(0)}, 5000);
this is the child process (located in child.js)
var FFI = require('node-ffi');
var current = new FFI.Library(null, {"prctl": ["int32", ["int32", "uint32"]]})
//1: PR_SET_PDEATHSIG, 15: SIGTERM
var returned = current.prctl(1,15);
process.on('SIGTERM',function(){
//do something interesting
process.exit(1);
});
doNotExit = function (){
return true;
};
setInterval(doNotExit, 500);
without the current.prctl(1,15) the child will run forever even if the parent is dying. Here it will be signaled with a SIGTERM which will be handled gracefully.

Could you just put an exit listener in the parent process that signals the children?
Edit:
You can also use node-ffi (Node Foreign Function Interface) to call ...
prctl(PR_SET_PDEATHSIG, SIGHUP);
... in Linux. ( man 2 prctl )

I start Node.JS from within a native OSX application as a background worker. To make node.js exit when the parent process which consumes node.js stdout dies/exits, I do the following:
// Watch parent exit when it dies
process.stdout.resume();
process.stdout.on('end', function() {
 process.exit();
});
Easy like that, but I'm not exactly sure if it's what you've been asking for ;-)

Related

Kill detached child process in Node

I'm not fully understand why I can't kill a detached process. Can someone help me out?
Server (child process)
const server = spawn(
'npm',
[
'run',
'watch:be',
],
{
detached: true,
},
);
Await for the server to up and running
await waitOn({
resources: [
`https://localhost:${process.env.SERVER_PORT}`,
],
delay: 1000,
timeout: 30000,
});
console.log('server is up and running');
Wait a couple more seconds
await new Promise((resolve, reject): void => {
setTimeout((): void => {
resolve();
}, 2000);
});
console.log('Run test');
Kill the child server
server.kill();
console.log('Shutdown server');
All of these are in the same file.
The child process opened a new terminal window (when it does spawn, which is expected), but doesn't close when kill. Can someone point out what I have done wrong?
server.kill();
As per the node.js documentation, The subprocess.kill() method sends a signal to the child process. When you use the detached option, the node creates a separate process group for the child process and it is not part of the same process anymore.
detached <boolean>: Prepare child to run independently of its parent process
That is the reason kill is not appropriate to use when detached is used.
This has been discussed here:
https://github.com/nodejs/node/issues/2098
As suggested in the above link, you should use process.kill to kill the process (https://nodejs.org/api/process.html#process_process_kill_pid_signal). This should probably work for you:
process.kill(-server.pid)
You said that "The child process opened a new terminal window ..."
Based on this behaviour, it seems that your OS is Windows.
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.
source
For process.kill, the second arg is the signal you want to send. By default, this signal is SIGTERM. However, SIGTERM doesn't seem to be supported on Windows, according to the Signal Events section of the Node.js docs.
'SIGTERM' is not supported on Windows, it can be listened on.
Maybe try
process.kill(server.pid, 'SIGHUP')
or
process.kill(server.pid, 'SIGINT')
(This works on macOS but I've not tried it on Windows.)

Node JS - Cannot Kill Process Executed with Child Process Exec

We are trying to kill the process of a chrome browser launched with nodes child_process exec command
var process = cp.exec(`"chrome.exe" --app="..."`, () => {}); // working great
But when we try
process.kill(); //nothing happens...
Does the process refer to the chrome window or something else? if not, how can we get a hold of the newly opened chrome window process, PID, etc...?
Any help would be great...
Note - we have tried using the chrome_launcher NPM but it didn't help because we couldn't open chrome in kiosk mode without fullscreen, but this is an issue for a different question...
Try the PID hack
We can start child processes with {detached: true} option so those processes will not be attached to main process but they will go to a new group of processes.
Then using process.kill(-pid) method on main process we can kill all processes that are in the same group of a child process with the same pid group. In my case, I only have one processes in this group.
var spawn = require('child_process').spawn;
var child = spawn('your-command', {detached: true});
process.kill(-child.pid);
I built a cross platform npm package that wraps up spawning and killing child processes from node, give it a try.
https://www.npmjs.com/package/subspawn
I am not able to add comment, so I am saying it directly in the answer:
How to kill process with node js
If you check the link above you need library as follows
https://www.npmjs.com/package/fkill
Usage Example taken from stackoverflow question
const fkill = require('fkill');
fkill(1337).then(() => {
console.log('Killed process');
});
fkill('Safari');
fkill([1337, 'Safari']);
I also found this library to check running processes
https://github.com/neekey/ps

process.send is conditionally defined in Node.js

For whatever reason, in Node.js, the function process.send is defined in some environments but not defined in others. For instance, when I fork a child process from a parent process in Node.js like so:
//parent process
var cp = require('child_process');
var k = cp.fork('./child.js',['arg1','arg2','arg3']);
k.send('fail'); //k.send is defined...
process.send("ok, let's try this..."); //process.send is NOT defined
inside the child process:
//child.js
process.send('message'); //process.send is defined, and will send a message to the parent process above
The only way I know how to get around this is:
if (typeof process.send === 'function') {
process.send('what I want to send');
}
Child processes have a process.send method to communicate back with the process that spawned them, while the root process doesn't have any "parent" to communicate, so its not there. From the docs:
In the child the process object will have a send() method, and process will emit objects each time it receives a message on its channel.
To avoid having to "litter the code with conditionals", a temporary solution might be to just put a "noop" function in its place at the top of any "root" files you might be spawning processes from:
process.send = process.send || function () {};
set a condition and call process.send in it
if(process.send){ process.send() }
Workaround for Sapper & Svelte usage:
Basically, this error can be received in flow when you provided SAPPER_EXPORT variable in your environment.
More details about issue: https://github.com/Zimtir/SENT-template/issues/114

Callback when a child_process has successfully processed a signal

I need to verify that a child_process has successfully been killed because I cannot execute the next action if that process is still alive.
var proc = require('child_process');
var prog = proc.spawn('myprog', ['--option', 'value']);
prog.on('data', function(data) {
// Do something
});
Somewhere else in the code I reach to a certain event and on a certain condition I need to kill prog:
prog.kill('SUGHUP');
// Only when the process has successfully been killed execute next
// Code...
Since kill is probably async, I am using q. I would like to use q on kill but kill does not have a callback which is executed when the signal has successfully been processed.
How to do?
Possible idea
If I send a message to process prog and in process prog when receiving the message I kill it? How can tell a process to self-kill?
Wouldn't prog.exec() with the option killsignal and a callback fit your needs ?

child process not calling close event

I have the following node.js code:
var testProcess = spawn(item.testCommand, [], {
cwd: process.cwd(),
stdio: ['ignore', process.stdout, process.stderr]
});
testProcess.on('close', function(data) {
console.log('test');
});
waitpid(testProcess.pid);
testProcess.kill();
however the close method never gets calls.
The end result I am looking for is that I spwan a process and the the script waits for that child processs to finish (which waitpid() is doing correctly). I want the output/err of the child process to be display to the screen (which the stdio config is doing correctly). I also want to perform code on the close of the child process which I was going to do in the close event (also tried exit), but it does not fire.
Why is the event not not firing?
http://nodejs.org/api/process.html
Note that just because the name of this function is process.kill, it is really just a signal sender, like the kill system call. The signal sent may do something other than kill the target process.
You can specify the signal while Kill() call.
Looking at waitpid() I found out that it returns an object with the exitCode. I changed my code so that I just perform certain actions based on what the value of the exitCode is.

Resources