Ensure child exits when parent does - node.js

I am spawning a child process in node and have sometimes noticed that the child process does not exit when the parent process exits.
var worker = child.fork(__dirname + '/process');
worker.on('exit', function(exitCode) {
if (exitCode != 0) {
start();
}
});
process.on('exit', function() {
worker.kill();
});
I am also trying to ensure that if the worker dies without a 0 error code it is started again. This seems to work just fine. However I have noticed that sometimes my child process is left hanging around after the parent is gone.
What exactly is 'process.on('exit'...' listening for? I.E. What happens when I press Ctrl-C, will exit pick that up? Do I need to listen for all parent exit signals?
Should I be listening for more on the child process as well? Like 'uncaughtException'?
Basically what is the proper way to launch a child process, ensure it stays up, but exits when the parent does?

Related

Node.js child process shutdown delay

I have a node.js process that kicks off a child process (via spawn). When the main process receives a request to shutdown (e.g. SIGTERM) it has to perform some clean-up before the process exits - this can take a few seconds. This clean-up relies on the child process continuing to run - however, the child process is independently responding to the SIGTERM and closing down.
Can I prevent the child process closing until the main process is ready for it to shutdown?
Thanks,
Neil
After spawning child processes in detached mode, you can handle them individually. This can be of use to you: Node child processes: how to intercept signals like SIGINT.
The following assumes your child processes are detached:
process.on('SIGINT', () => {
console.log("Intercepted SIGINT on parent");
// Do your magic here, if you just need to wait for X time, you can use a delay promise:
delay(5000).then(() => {
// Kill/handle your child processes here
process.exit(0); // Then exit the main process
});
});
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

end child gracefully when doing Ctrl-C in NodeJS

I have a architecture with one parent that spawns a child as follow :
this.process = child.spawn(this.cmd, this.args);
this.process.on('exit', (code: number, signal: string) => {
this.exitCode = code;
console.log(`exit code: ${code}`);
});
there is no particular option because i want to keep a link with the child. So, when i press Ctr-C to kill the parent, it catches SIGINT to (1) end the child, (2) exit properly. But SIGINT is also propagated to the child, so the parent cannot end it gracefully. So, is there a way to do so ? maybe by preventing SIGINT to be propagated to the child ? or telling the child to ignore the signal ?
i know that something is possible by adding option detached: true and stdio: 'ignore' when spawning, but i don't want to do that because if the parent dies, i end up with zombies process. Whereas keeping the links ensure that the child is killed if the parent dies unexpectedly. Finally, i want to avoid catching SIGINT in the child as i want to keep it dumb.
EDIT: the parent already have a process.on('SIGINT', () => { ... } and the child is in python.
You can catch exit codes like this:
process.on('SIGINT', () => {
// handle it yourself
})
You can propagate it to children like so:
process.on('SIGINT', () => {
this.child.kill('SIGINT')
})
The child can of course also choose to handle the signal, it is wise to not assume the child process will exit simply because you sent a single signal. You may need to set a timeout and send repeat or different signals to fully kill a process. You will also want to listen to the 'exit' message of the child process to know when its actually killed before continuing.
Documentation
Process Signal Events
Kill Sub-Process With Signal

Detach a spawn child process after the start

I start a spawn child process this way:
let process = spawn(apiPath, {
detached: true
})
process.unref()
process.stdout.on('data', data => { /* do something */ })
When I start the process I need to keep it attached because I want to read its output. But just before closing my Node process (the parent) I want to detach all not finished children processes to keep them running in background, but as the documentation say:
When using the detached option to start a long-running process, the process will not stay running in the background after the parent exits unless it is provided with a stdio configuration that is not connected to the parent.
But with the option stdio: 'ignore' I can't read the stdout which is a problem.
I tried to manually close the pipes before to close the parent process but it is unsuccessful:
// Trigger just before the main process end
process.stdin.end()
process.stderr.unpipe()
process.stdout.unpipe()
After many tests I found at least one way to solve this problem : destroying all pipe before to leave the main process.
One tricky point is that the child process have to handle correctly the pipes destroying, if not it could got an error and close anyway. In this example the node child process seems to have no problem with this but it could be different with other scenario.
main.js
const { spawn } = require('child_process')
console.log('Start Main')
let child = spawn('node', ['child.js'], { detached: true })
child.unref() // With this the main process end after fully disconnect the child
child.stdout.on('data', data => {
console.log(`Got data : ${data}`)
})
// In real case should be triggered just before the end of the main process
setTimeout(() => {
console.log('Disconnect the child')
child.stderr.unpipe()
child.stderr.destroy()
child.stdout.unpipe()
child.stdout.destroy()
child.stdin.end()
child.stdin.destroy()
}, 5000)
child.js
console.log('Start Child')
setInterval(function() {
process.stdout.write('hello from child')
}, 1000)
output
Start Main
Got data : Start Child
Got data : hello from child
Got data : hello from child
Got data : hello from child
Got data : hello from child
Disconnect the child

How to catch child_process restarting/forking itself

I am trying to get a node script to run another command with child_process, which starts up a server, but this server has 'live reload' functionality.
As far as I understand, as soon as anything changes, the child process restarts, and my parent process continues as if the child died/exited.
I want my parent process to re-connect to a newly forked/spawned child.
Is there any way to do this?
const command = 'server --listen 7070';
const process = child_process.exec(command);
process.stdout.on('data', (data) => {
console.log(data);
});
process.on('exit', (event) => {
console.log('The child process exited')
});
In this example, the server keeps running, but the stdout processing stops after the child process restarts itself for the first time.

Node child process can not run detached

I'm trying to fork a node child process with
child_process.fork("child.js")
and have it say alive after the parent exits. I've tried using the detached option like so:
child_process.fork("child.js", [], {detached:true});
Which works when using spawn, but when detached is true using fork it just fails silently, not even executing the child.js.
I've also tried
var p = child_process.fork("child.js")
p.disconnect();
p.unref();
But child still dies when the parent does.
Any help or insight would be greatly appreciated.
EDIT:
Node Version: v5.3.0
Platform: Windows 8.1
Code:
//Parent
var child_process = require("child_process");
var p;
try{
console.log(1)
p = child_process.fork("./child.js")
console.log(2)
} catch(e){
console.log(e)
}
p.on('error', console.log.bind(console))
p.disconnect();
p.unref();
//To keep process alive
setTimeout(() => {
console.log(1);
}, 100000);
--
//Child
var fs = require("fs");
console.log(3);
fs.writeFileSync("test.txt", new Date().toString());
setTimeout(()=>{
console.log(1);
}, 100000);
I'm assuming you're executing your parent file from the command line, which is probably why it "appears" that the forked child is not executing. In reality when the parent process exits, the terminal stops waiting and thus prints a new line, waiting for your next command. This makes it seem like the child isn't executing, but trust me it is. Also there is no "detached" option for child_process.fork
Add some console.log() statements to your child process and you should see input printing in your terminal even after the parent has exited. If you don't it's because your child is prematurely exiting due to an error. Run your child process directly to debug it, before calling it from the parent.
Check out this quick example:
Hope this helps.

Resources