Hattori
Hattori

Reputation: 371

Catch SIGINT in parent but kills child anyway

I have a architecture with one parent that spawns tow childs (one in c++ the other in python). The parent spawns with the following class :

export class subProcess {
    protected cmd: string;
    protected args: string[];
    protected process: child.ChildProcess;

    constructor(cmd: string, args: string[]) {
        this.cmd     = cmd;
        this.args    = args;
        this.process = null;
    }

    spawn(): void {
        this.process = child.spawn(this.cmd, this.args);

        const rlout = readline.createInterface({
            input: this.process.stdout,
        });
        rlout.on('line', line => this.logger.info(line));

        const rlerr = readline.createInterface({
            input: this.process.stderr,
        });
        rlerr.on('line', line => this.logger.error(line));

        this.process.on('exit', (code: number) => {
            this.logger.info(`exit code: ${code}`);
        });
    }

When I interrupt the parent whith a Ctrl-C, signal SIGINT is caugth in the parent process to be able to first disconnect and kill the childs gracefully :

process.on('SIGINT', () => {
    this.bus.disconnect();
});

disconnect is a function that sends an "exit_process" command to the childs via ZeroMQ. This command works perfectly fine in normal behavior. But the problem is that when I press Ctrl-C, the SIGINT is caugth by the Parent and it executes disconnect function (as expected) but it seems that it also propagate SIGINT to the childs. Indeed, the "exit_process" command sent via ZeroMQ reaches it's timeout (which means that the childs have never received/answered) whereas the childs emit a returned code via the exit event.

The point is that I can't detache and/or unref the childs, or manage signals in childs, for project reasons. And I expected the parent to catch the SIGINT whithout propagating it to the childs.

One more point, I tried to add the following in subProcess class, but it did not work :

this.process.on('SIGINT', () => {
    console.log('SIGINT received. Do nothing');
});

Upvotes: 1

Views: 227

Answers (1)

cmbuckley
cmbuckley

Reputation: 42458

Your SIGINT is being passed to the entire process group — see this section on Wikipedia. However, you're probably not seeing any output because of how the child process pipes are established.

When spawning a new child process, you can provide stdio options:

this.process = child.spawn(this.cmd, this.args, {stdio: 'inherit'});

The above causes the parent's process.stdin, process.stdout, process.stderr to be inherited by the child process. If you use this approach, you will see that your child is receiving the SIGINT.

The default behaviour is to create separate streams, which is why you are not seeing your console.log. You could also listen to the child's stdout stream:

this.process.stdout.on('data', data => console.log(data.toString()));

Upvotes: 1

Related Questions