web-dev-qa-db-fra.com

Générer et tuer un processus dans node.js

Je pourrais être rétrogradé pour cela, mais je ne comprends pas où je me trompe.

J'essaie de générer un processus en javascript et de le tuer après un certain temps (pour le test).

En fin de compte, le processus sera une boucle infinie que je dois redémarrer avec différents arguments à une heure précise. Je pensais donc que créer et tuer le processus était la meilleure façon de le faire.

Mon code de test est:

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

Le résultat est:

#~$ node test.js
Timeout
kill

Mais je dois encore envoyer ctrl + C pour terminer le programme

Qu'est-ce que je rate?

EDIT: Sur Raspbian, noeud 0.10.17, omxplayer est un binaire (lecteur vidéo).

Essayé: Ajouté chmod + x à l'application . Lancé en tant que root . Stdin en pause du processus enfant. Utilisation de tous les signaux liés à la terminaison dans la commande kill.

EDIT2:

Lancement d'une commande ps pendant l'exécution de l'application:

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

Donc, omxplayer est un wrapper qui ne termine pas le processus à la fin. Y at-il un moyen d’obtenir le pid du processus emballé?

EDIT3:

Toujours mordant la poussière, a essayé ceci:

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

Ce qui, à mon avis, tuerait tous les enfants d’OMXplayer, je ne sais pas si utiliser spawn de la sorte est faux ou si c’est le code qui ne fonctionne pas.

Dernière édition:

La dernière modification que j'ai faite était la bonne réponse, mais a du être trompée un peu.

J'ai créé un fichier sh (avec exécuter à droite) comme ceci:

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

Que je commence comme ça:

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

Au lieu de child.kill.

Je ne suis pas sûr que ce soit la meilleure façon de procéder, ni si le code est propre, mais cela fonctionne.

J'accepterai toute réponse qui la rende plus propre ou meilleure sans avoir à exécuter de fichier.

40
DrakaSAN

Reportez-vous à cette discussion

Une fois que vous avez commencé à écouter les données sur stdin, le noeud attendra l’entrée sur stdin jusqu’à ce qu’on lui dise de ne pas le faire. Lorsque l'utilisateur appuie sur ctrl-d (la fin de la saisie) ou que le programme appelle stdin.pause (), le noeud cesse d'attendre le stdin.

Un programme de nœud ne se ferme que s'il n'a rien à faire ou à attendre. Ce qui se passe, c’est qu’il attend stdin et ne quitte donc jamais.

Essayez de changer votre rappel setTimeout en 

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

J'espère que ça devrait marcher.

39
robinkc

Il existe un npm package appelé tree-kill très soigné, qui le fait très facilement et efficacement. Il tue le processus enfant, et tous les processus enfants que cet enfant a pu démarrer.

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);
});
14
Michael Hall

J'ai eu exactement le même problème que vous avec omxplayer et la solution de cet article de blog a fonctionné pour moi.

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

Pourquoi n'envoyez-vous pas simplement la valeur 'q' dans le tube stdin? Cela tue le processus omxplayer.

1
Superdrac

Vous avez généré un processus enfant qui a été tué avec succès. Cependant, votre thread principal est toujours en cours d'exécution, c'est pourquoi vous devez appuyer sur Ctrl + C.

0
apscience

Essayez d’utiliser la méthode child_process.execFile() à partir de ici .

La fonction child_process.execFile () est similaire à child_process.exec () sauf qu'il ne génère pas de shell. Plutôt, le fichier exécutable spécifié est créé directement en tant que nouveau processus ce qui le rend légèrement plus efficace que child_process.exec ().

Cela fonctionne dans mon cas.

0
Stinger112

Enfin, j'ai trouvé comment le faire sans script:

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