在node.js中生成并终止进程

时间:2013-09-09 08:54:21

标签: javascript node.js

我正在尝试在javascript中生成一个进程,并在一段时间后将其终止(出于测试目的)。

最后,进程将是一个无限循环,我需要在指定时间使用不同的参数重新启动,所以我认为产生进程并终止它是最好的方法。

我的测试代码是:

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);
});

结果是:

#~$ node test.js
Timeout
kill

但是我仍然需要发送ctrl + C来结束程序。我错过了什么?

在Raspbian节点0.10.17上,omxplayer是二进制(视频播放器)。

我试过了:

  • 在应用中添加了chmod +x
  • 以root身份发布。
  • 暂停了子进程的标准输入。在kill命令中使用所有与终止相关的信号。

我还在应用运行时启动了ps命令:

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

所以omxplayer是一个包装器,当它结束时不会杀死它的子进程,有没有办法得到包装进程的pid?

仍然咬着灰尘,试了一下:

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

我认为会杀死omxplayer的所有孩子,我不知道使用这样的spawn是错误的还是代码不起作用。

我做的最后一次编辑是一个很好的答案,但不得不进行一些编辑。

我创建了一个sh文件(执行权限),如下所示:

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

我从这样开始:

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

而不是child.kill

我不确定这是不是最好的方法,也不确定代码是否干净,但确实有效。

我会接受任何以更清洁的方式提供的答案,或者甚至更好,无需执行文件。

8 个答案:

答案 0 :(得分:41)

请参阅this discussion

一旦开始在stdin上监听数据,节点将等待stdin上的输入,直到被告知不要。当用户按下ctrl-d(表示输入结束)或程序调用stdin.pause()时,节点将停止等待stdin。

除非没有任何操作或等待,否则节点程序不会退出。发生的事情是,它正在等待stdin,因此永远不会退出。

尝试将setTimeout回调更改为

console.log('kill');
child.stdin.pause();
child.kill();

我希望这应该有用。

答案 1 :(得分:18)

有一个非常简洁的npm package,名为t,可以非常轻松有效地完成这项任务。它会杀死子进程,子进程可能已经启动的所有子进程。

tree-kill

答案 2 :(得分:8)

我与omxplayer的问题完全相同,this blog post中的解决方案对我有用。

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);

答案 3 :(得分:2)

为什么不发送' q' stdin管道中的值?它会杀死omxplayer进程。

答案 4 :(得分:0)

您已经催生了一个成功杀死的子进程。但是,您的主线程仍在执行,这就是您必须按Ctrl + C。

的原因

答案 5 :(得分:0)

最后,我找到了没有脚本的方法:

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

答案 6 :(得分:0)

尝试使用here中的child_process.execFile()方法。

  

child_process.execFile()函数类似于   child_process.exec()除了它不生成shell。相反,   指定的可执行文件直接作为新进程生成   使它比child_process.exec()稍微高效。

它适用于我的情况。

答案 7 :(得分:0)