'Spawn and kill a process in node.js

I'm trying to spawn a process in javascript, and kill it after some time (for testing purposes).

In the end, the process will be a infinite loop that I need to restart with different arguments at specified time, so I thought that spawning the process and killing it was the best way to do this.

My test code is:

var spawn=require('child_process').spawn
, child=null;

child=spawn('omxplayer', ['test.mp4'], function(){console.log('end');}, {timeout:6000});
console.log('Timeout');
setTimeout(function(){
    console.log('kill');
    child.kill();
}, 1200);

child.stdout.on('data', function(data){
    console.log('stdout:'+data);
});

child.stderr.on('data', function(data){
    console.log('stderr:'+data);
});

child.stdin.on('data', function(data){
    console.log('stdin:'+data);
});

The result is:

#~$ node test.js
Timeout
kill

But I still need to send ctrl+C to end the program. What am I missing?

On Raspbian, node 0.10.17, omxplayer is a binary (video player).

I tried:

  • Added chmod +x to the app.
  • Launched as root.
  • Paused stdin of the child process. Using all terminate-related signal in the kill command.

I also launched a ps command while the app was running:

2145    bash
2174    node
2175    omxplayer
2176    omxplayer.bin
2177    ps

So omxplayer is a wrapper, who don t kill it's child process when it end, is there any way to get the pid of the wrapped process?

Still biting dust, tried this:

spawn('kill', ['-QUIT', '-$(ps opgid= '+child.pid+')']);

Which I thought would kill all children of omxplayer, I don t know if using spawn like that is wrong or if it's the code that doesn't work.

The last edit I made was the good answer, but had to be edited a bit.

I created a sh file (with execute right) like this:

PID=$1
PGID=$(ps opgid= "$PID")
kill -QUIT -"$PGID"

Which I start like this:

execF('kill.sh', [child.pid], function(){
    console.log('killed');
});

Instead of child.kill.

I'm not sure if it s the best way to do, nor if the code is clean, but it does work.

I'll accept any answer which make it in a cleaner way or, even better, without having to execute a file.



Solution 1:[1]

There is a really neat npm package called tree-kill which does this very easily and effectively. It kills the child process, and all child processes that child may have started.

var kill  = require('tree-kill');
const spawn = require('child_process').spawn;

var scriptArgs = ['myScript.sh', 'arg1', 'arg2', 'youGetThePoint'];
var child = spawn('sh', scriptArgs);

// some code to identify when you want to kill the process. Could be
// a button on the client-side??
button.on('someEvent', function(){
    // where the killing happens
    kill(child.pid);
});

Solution 2:[2]

I've had exactly the same issue as you with omxplayer and the solution in this blog post worked for me.

var psTree = require('ps-tree');

var kill = function (pid, signal, callback) {
    signal   = signal || 'SIGKILL';
    callback = callback || function () {};
    var killTree = true;
    if(killTree) {
        psTree(pid, function (err, children) {
            [pid].concat(
                children.map(function (p) {
                    return p.PID;
                })
            ).forEach(function (tpid) {
                try { process.kill(tpid, signal) }
                catch (ex) { }
            });
            callback();
        });
    } else {
        try { process.kill(pid, signal) }
        catch (ex) { }
        callback();
    }
};

// elsewhere in code
kill(child.pid);

Solution 3:[3]

Why don't you just send the 'q' value in the stdin pipe ? It kill the omxplayer process.

Solution 4:[4]

You've spawned a child process which was successfully killed. However, your main thread is still executing, which is why you have to press Ctrl+C.

Solution 5:[5]

Finally, I found how to do it without script:

exec('pkill omxplayer', function(err, stdout, stderr){
    if (stdout){console.log('stdout:'+stdout);}
    if (stderr){console.log('stderr:'+stderr);}
    if (err){throw err;}
    //...
}

Solution 6:[6]

Try to use child_process.execFile() method from here.

The child_process.execFile() function is similar to child_process.exec() except that it does not spawn a shell. Rather, the specified executable file is spawned directly as a new process making it slightly more efficient than child_process.exec().

It works in my case.

Solution 7:[7]

You must specify the signal:

child.kill('SIGKILL')

https://nodejs.org/api/child_process.html#child_process_subprocess_kill_signal

Solution 8:[8]

In node:16 I was required to destroy() (pause() i not enough) the std channels before sending kill(). Like this:

cmd.stdout.destroy();
cmd.stderr.destroy();
cmd.kill('SIGINT');

See how exec() source code handles kill()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 mikenolan
Solution 3 Superdrac
Solution 4 apscience
Solution 5 Rajesh Ujade
Solution 6 Community
Solution 7 Dharman
Solution 8