【问题标题】:Can't kill child process on Windows无法杀死 Windows 上的子进程
【发布时间】:2015-09-21 23:01:17
【问题描述】:

以下永远不会退出

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

【问题讨论】:

  • 这篇文章的帮助:stackoverflow.com/a/20189473/121946
  • @AdrianLynch 并非如此,投票最高的答案只是指向child_process.kill。使用外壳包装器时,该过程不会仅因这一点而死。
  • 也许有些东西正在捕捉默认的 SIGTERM (github.com/nodejs/node/blob/master/lib/internal/…) 信号。如果你想让它立即被杀死,你可以试试ps.kill('SIGKILL')
  • 很确定我跑过 SIGKILL、SIGTERM 和 SIGINT 但我会仔细检查。
  • 也许能给我们更多关于你真正想要做什么的背景信息?

标签: node.js


【解决方案1】:

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

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


更新:

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

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

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

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. 使用带有\T 标志的windows taskkill 命令杀死进程和由它启动的所有子进程:

    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

【讨论】:

  • cmd.exe 及其子 node.exe 在查看进程树时都会被杀死..?
  • 这可能是父node.exe。你是如何观察树的?您可以使用流程资源管理器。
  • 父 node.exe 一直存在所以不,确定子进程 cmd.exe 及其子 node.exe 被杀死(是的,用进程资源管理器观察)
  • 你的脚本除了运行 babel 命令还做其他事情吗?我确实使用修复程序运行了您的示例脚本,并且所有进程都正常终止。
  • 我指的是使用 stdio: 'pipe' 的简化测试用例。 Taskkill 会起作用,但这不只是解决问题的方法吗?为什么进程(孙节点)似乎以“继承”而不是“管道”终止?让这个答案更好。深入探讨原因而不是解决方法。您还可以取消引用子进程,这将使父进程退出从而杀死一切。
【解决方案2】:

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

我使用child_process.spawn()启动一个服务(自定义HTTP服务器service.windows):

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') 是不可能的。 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

好的,我尝试再次使用T 标志终止cp。和繁荣,不可能。 cp 是我的主要 node.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 文档没有说明如何处理这个问题。他们只会说“是的,我们知道存在问题,我们只是通知您”。

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 不认为它适合这种情况。这不是适用于我的解决方案,但它是一个解决方案。
    • 实际上子进程在这样做时似乎继续运行。
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2019-07-09
      • 2017-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多