Не удается убить дочерний процесс В Windows

следующее Никогда не выйдет

var child_process = require('child_process');

var ps = child_process.spawn('.node_modules.binbabel.cmd', ['input.js', '--out-file', 'output.js', '--watch']);

ps.on('exit', function() {
  console.log('exit');
});

ps.on('close', function() {
  console.log('close');
});

setTimeout(function () {
  ps.kill();
}, 2000);

что здесь происходит? и что здесь правильно делать? Единственный способ сделать этот процесс действительно близким-убить родительский процесс. Я подозреваю, что он ждет, когда stdio спустит воду или что-то в этом роде?

Он умирает, если ему дают 'ignore' конфигурация stdio, но мне нужны потоки.

var ps = child_process.spawn('.node_modules.binbabel.cmd', ['test.js', '--out-file', 'output.js', '--watch'], {
    stdio: 'ignore'
});

4 ответов


вы нерест ребенка процесс cmd.exe С помощью babel.cmd. Затем этот процесс запускает другой процесс внука node и запускает сценарий babel. Когда вы делаете ps.kill() он убивает только cmd.exe но не дочерние процессы, созданные им.

хотя cmd.exe закрыт, поток stdio родительского процесса по-прежнему совместно используется с другими процессами в дереве. Таким образом, родительский процесс ожидает закрытия потока. Используя stdio: 'ignore' остановит только совместное использование stdio поток с другими процессами в дереве, но эти процессы внука по-прежнему будут работать.


обновление:

после обсуждения с OP я протестировал все три варианта stdio:pipe(по умолчанию), inherit, ignore в iojs 3.3.0, Windows 7 (32bit). никто из них не убивает внука процесса.

С inherit и ignore, как родительский процесс, так и дочерний процесс(cmd.exe) убиты, но Гранд дочерний процесс по-прежнему плавает и не принадлежит ни к одному дереву процессов.

С pipe, завершается только дочерний процесс, но Родительский и дочерний процесс продолжают работать. Причина, по которой родительский процесс не выходит, скорее всего, потому, что stdio родительского узла.exe по-прежнему используется совместно с другими процессами, как указано в исходном ответе.

child.unref() не оказывает никакого влияния на процесс убийства великого ребенка. Он удаляет только дочерний процесс из цикла событий родителя, чтобы родительский процесс мог выйти нормально.


я мог бы придумать пару решений:

  1. вызов babel.js непосредственно без этого сценария cmd:

    var ps = child_process.spawn('node', ['.\node_modules\babel\bin\babel.js', 'input.js', '--out-file', 'output.js', '--watch'])
    
  2. использовать windows С \T флаг, чтобы убить процесс и все дочерние процессы, запущенные им:

    os = require('os');
    if(os.platform() === 'win32'){
        child_process.exec('taskkill /pid ' + ps.pid + ' /T /F')
    }else{
        ps.kill();  
    }
    

    есть некоторые модули npm, которые могут обрабатывать дочерние процессы убийства в обоих Unix и Windows, например,tree-kill. Для windows он использует taskkill или tasklist.


одним из потенциальных решений является вызов ReadableStream.end или ReadableStream.destroy


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

для unix скрипт является исполняемым файлом npm. Для windows, однако, нам нужно решить имя из .файл cmd.

if (path.extname(command).toLowerCase() == '.cmd') {
  var content = '' + fs.readFileSync(command);
  var link = (/node  "%~dp0\(.*?)"/.exec(content) || [])[1];

  if (link) {
    command = path.resolve(path.dirname(command), link);
  }
}

var ps = child.spawn('node', [command].concat(args), options);

у меня такая же проблема в Windows (Win 10 64x). Я не могу прервать процесс порожденного дочернего процесса.

я запускаю службу (пользовательский HTTP-сервер service.windows) через child_process.spawn():

const { spawn } = require('child_process');
let cp = spawn('"C:\Users\user\app\service.windows"', [], { shell: true,  });

cp.stderr.on('data', (data) => {
    console.log(`stderr: ${data}`);
    console.log('cp.connected', cp.connected);
    console.log('process.pid', process.pid); // 6632 <<= main node.js PID
    console.log('cp.pid', cp.pid); // 9424 <<= child PID

    // All these are useless, they just kill `cp`
    cp.kill('SIGINT'); // Doesn't terminate service.windows
    cp.kill('SIGKILL'); // Doesn't terminate service.windows
    cp.kill('SIGTERM'); // Doesn't terminate service.windows
});

и я хочу завершить свою службу HTTP-сервера (service.windows). И это невозможно в Windows, используя cp.kill('ANY SIGNAL'). Узел.js убивает свой дочерний процесс (cp), но мой HTTP-сервер (service.windows) все еще работает нормально.

когда я проверяю его в другом терминале, я вижу, что мой сервер работает просто отлично:

$ netstat -ano | findstr :9090
  TCP    0.0.0.0:9090           0.0.0.0:0              LISTENING       1340
  TCP    [::]:9090              [::]:0                 LISTENING       1340

я пытаюсь вручную убить свой сервер PID но с T флаг, а не F. Разница:

T завершите все дочерние процессы вместе с родительским процессом, обычно известным как убийство дерева.

F процесс (ы) будет принудительно прекращен.

$ taskkill -T -PID 1340
ERROR: The process with PID 1340 (child process of PID 9424) could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).

и он точно говорит, что мой сервер 1340 - дитя, что cp - PID 9424.

хорошо, я пытаюсь завершить это cp используя T снова флаг. И бум, невозможно. cp - дитя мое основное узла.js process.pid 6632:

$ taskkill -T -PID 9424
ERROR: The process with PID 1340 (child process of PID 9424) could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).
ERROR: The process with PID 9424 (child process of PID 6632) could not be terminated.
Reason: One or more child processes of this process were still running.

я могу убить его только силой F флаг:

$ taskkill -F -T -PID 9424
SUCCESS: The process with PID 1340 (child process of PID 9424) has been terminated.
SUCCESS: The process with PID 9424 (child process of PID 6632) has been terminated.

самое разочаровывающее-Это этот узел.JS docs не говорит jack ship о том, как справиться с этой проблемой. Они только говорят: "Да, мы знаем, что проблема существует, и мы просто сообщаем вам об этом".

единственный вариант, который я вижу в Windows, - использовать taskkill -F -T -PID 9424 в расплодили процесс:

exec('taskkill -F -T -PID 9424');