Подтвердить что ты не робот

Создайте и уничтожьте процесс в 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.
  • Приостановлено stdin дочернего процесса. Использование всех связанных с завершением сигналов в команде 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.

Я не уверен, является ли это лучшим способом, или если код чист, но он работает.

Я приму любой ответ, который сделает его более понятным или, что еще лучше, без необходимости выполнения файла.

4b9b3361

Ответ 1

Обратитесь к этой дискуссии

Как только вы начнете прослушивать данные на stdin, node будет ждать ввода на stdin, пока не будет сказано. Когда пользователь нажимает ctrl-d (что означает конец ввода), или программа вызывает stdin.pause(), node перестает ждать на stdin.

Программа node не выходит, если ей нечего делать или ждать. Что происходит, он ждет на stdin и поэтому никогда не выходит.

Попробуйте изменить обратный вызов setTimeout на

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

Я надеюсь, что это сработает.

Ответ 2

Существует действительно опрятный npm package под названием tree-kill, который делает это очень легко и эффективно. Он убивает дочерний процесс и все дочерние процессы, которые ребенок мог запустить.

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

Ответ 3

У меня была точно такая же проблема, как у вас с omxplayer, и решение для этого сообщения в блоге работало для меня.

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

Ответ 4

Почему бы вам просто не отправить значение "q" в трубе stdin? Это убивает процесс omxplayer.

Ответ 5

Вы создали дочерний процесс, который был успешно убит. Тем не менее, ваш основной поток все еще выполняется, поэтому вам нужно нажать Ctrl + C.

Ответ 6

Наконец, я нашел, как это сделать без script:

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

Ответ 7

Попробуйте использовать child_process.execFile() метод здесь.

Функция child_process.execFile() похожа на child_process.exec(), за исключением того, что он не создает оболочку. Скорее, указанный исполняемый файл генерируется непосредственно как новый процесс что делает его несколько более эффективным, чем child_process.exec().

Это работает в моем случае.