3

I have NodeJS code like the following:

[myFile.js]

var path  = require("path");
var cp  = require("child_process");
var child = cp.spawn( "python",["HelloWorld.py"], { stdio:'pipe', });

child.stdout.on('data', (data) => {
    console.log(`CHILD stdout: ${data }`);
});

child.stderr.on('data', (data) => {
  console.log(`CHILD stderr: ${data}`);
});

process.on("SIGINT",()=>{
    // close gracefully
    console.log("Received SIGINT");
})
child.on('exit',(code)=>{console.log(`child Process exited with code ${code}`)})

and python script like:

[HelloWorld.py]

print 'Hi there'
import time
time.sleep(5)

I want to manage the shutdown gracefully, but when I start this code at the command line via:

> node myFile.js

and press control-C, I get this printed to the console:

^CReceived SIGINT
CHILD stdout: Hi there

CHILD stderr: Traceback (most recent call last):
  File "HelloWorld.py", line 3, in <module>
    time.sleep(5)
KeyboardInterrupt

child Process exited with code 1

indicating that python (running in the child process) received the '^C' keyboard event. However, I'd prefer exit the child process a bit more gracefully, rather than crashing on a keyboard interrupt.

I tried a variety of combinations for the options.stdio, including [undefined,'pipe','pipe'] (which didn't work), and ['ignore','pipe','pipe'] (which caused the child process to crash), and I tried worker.stdin.end() (which also caused the child process to crash).

Is there a way to not inherit the standard in from the parent NodeJS process?

Jthorpe
  • 9,756
  • 2
  • 49
  • 64
  • Are you against catching the exception in your python script? If not, you can wrap it in a `try` `catch` statement to silence the error. See: http://stackoverflow.com/questions/7073268/remove-traceback-in-python-on-ctrl-c – Mike Jan 21 '17 at 02:15
  • 1
    Good point, but my question is about NodeJS, not Python. I'm using python in the above example because (A) it makes it clear that the KeyboardInterupt is being passed to the child process, and (B) the code i'm writing is for a generalized task runner, and it's not possible to inject try/catch in every script and language that will be run in the child process -- better to prevent the interrupt from being sent to the child process in the first place. – Jthorpe Jan 21 '17 at 04:52

1 Answers1

4

RTFM: setting options.detached to true is what prevents propagating the kill signals, which (surprise) is how attached child processes are killed when the parent is killed...

Jthorpe
  • 9,756
  • 2
  • 49
  • 64
  • 4
    (If you downvote due to snark, please realize I was answering my own question...) – Jthorpe Oct 15 '18 at 04:03
  • I'll admit I downvoted it.I did not realize that you answered to yourself, sorry about that. I can remove the downvote, but you have edit your answer. – RoyalBingBong Oct 18 '18 at 13:54
  • 2
    Also worth mentioning, that `^C` in the terminal sends `SIGINT` to the whole process group. If you `kill` the main process manually, then you should be able to gracefully stop the child processes without them needing to be detached. Similar things happens with systemd.service, but there you can set the `KillMode`. – RoyalBingBong Oct 18 '18 at 14:01