无法在Windows上杀死子进程

时间:2015-09-21 23:01:17

标签: node.js

以下内容永远不会退出

var child_process = require('child_process');

var ps = child_process.spawn('.\\node_modules\\.bin\\babel.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\\.bin\\babel.cmd', ['test.js', '--out-file', 'output.js', '--watch'], {
    stdio: 'ignore'
});

4 个答案:

答案 0 :(得分:21)

您正在使用cmd.exe生成子进程babel.cmd。然后,此过程启动另一个孙进程node并运行babel脚本。执行ps.kill()时,它只会杀死cmd.exe,但不会杀死由它创建的子进程。

虽然cmd.exe已关闭,但父进程的stdio流仍与树中的其他进程共享。因此父进程正在等待关闭流。使用stdio: 'ignore'只会停止与树中的其他进程共享stdio流,但这些孙进程仍将继续运行。

更新:

在与OP讨论后,我测试了所有三个stdio选项:iojs 3.3.0,Windows 7(32位)中的pipe(默认),inheritignore他们都没有杀死孙子进程

使用inheritignore,父进程和子进程(cmd.exe)都被终止,但是子进程仍然浮动并且不属于任何进程树。

使用pipe时,只有子进程被终止,但父进程和子进程都继续运行。父进程未退出的原因很可能是因为父node.exe的stdio仍与原始答案中提到的其他进程共享。

child.unref()对杀死大孩子进程没有任何影响。它只从父事件循环中删除子进程,以便父进程可以正常退出。

我能想到几个解决方案:

  1. 在没有该cmd脚本的情况下直接调用babel.js

    var ps = child_process.spawn('node', ['.\\node_modules\\babel\\bin\\babel.js', 'input.js', '--out-file', 'output.js', '--watch'])
    
  2. 使用带有taskkill标志的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,它使用taskkilltasklist

答案 1 :(得分:1)

一种可能的解决方案是致电ReadableStream.endReadableStream.destroy

答案 2 :(得分:1)

最直接的解决方案,不要生成脚本而是直接生成节点。

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

答案 3 :(得分:0)

我在Windows上遇到了同样的问题(Win 10 64x)。我无法终止衍生的子进程的过程。

我使用service.windows启动服务(自定义HTTP服务器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)。在使用cp.kill('ANY SIGNAL')的Windows上无法实现。 Node.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).

它确切地说我的服务器1340cp - 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.

最令人失望的是,Node.js文档并没有说明如何处理这个问题。他们只是说'是的,我们知道这个问题存在,我们只是告诉你这个问题&#34;。

我在Windows上看到的唯一选项是在生成的进程中使用taskkill -F -T -PID 9424

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