Создайте и уничтожьте процесс в 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
.
Я не уверен, является ли это лучшим способом, или если код чист, но он работает.
Я приму любой ответ, который сделает его более понятным или, что еще лучше, без необходимости выполнения файла.
Ответы
Ответ 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().
Это работает в моем случае.