为啥我通过 spawn() 创建的 Node 子进程挂起?

Posted

技术标签:

【中文标题】为啥我通过 spawn() 创建的 Node 子进程挂起?【英文标题】:Why is my Node child process that I created via spawn() hanging?为什么我通过 spawn() 创建的 Node 子进程挂起? 【发布时间】:2014-01-14 13:23:06 【问题描述】:

我正在使用 spawn() 进行 git 调用。有时它可以正常工作,但有时它似乎挂起。我没有看到任何事件触发(错误、退出、关闭),但我看到了该过程确实成功完成的证据。

var spawn = require('child_process').spawn;

spawn('git', ['push', 'origin', 'master'])
  .on('error', function(error) 
    console.log("ERROR: DETAILS: " + error);
  )
  .on('close', function(code) 
    console.log("SUCCESS: CODE: " + code);
  )
  .on('exit', function(code) 
    console.log("EXIT: CODE: " + code);
  )

【问题讨论】:

【参考方案1】:

事实证明,一旦 stderr 缓冲区超过 24kb,您必须从中读取,否则您将看不到任何完成事件。可能的解决方法:

    在 spawn 调用中设置 stdio 选项。

    spawn('git', ['push', 'origin', 'master'], stdio: 'ignore');
    

    请参阅 Node ChildProcess 文档了解所有可能性 - 有很多。

    添加一个 on(data) 处理程序。

    var git = spawn('git', ['push', 'origin', 'master']);
    ...
    git.stderr.on('data', function(data) 
      // do something with it
    );
    

    通过管道将其传输到标准输出/标准错误。这对您的应用程序来说可能过于冗长,但为了完整性而将其包含在内。

    var git = spawn('git', ['push', 'origin', 'master']);
    ...
    git.stderr.pipe(process.stderr);
    git.stdout.pipe(process.stdout);
    

【讨论】:

this Node issue 中包含一个可重现的案例。我相信 exit 不会触发这一事实是一个错误,因为缓冲区的大小会导致不同的行为。 事实证明,这正是使用子进程时的方式。您必须对 stdio 管道做一些事情,否则会冒着子进程挂起的风险,因为它的管道已满。另见this thread。 在这种情况下,孩子没有挂,它已经退出了。但是,节点代码不接收任何事件。我在子进程消失的地方看到了同样的事情,但是节点从不触发退出或关闭事件,并且我的节点代码死锁等待发生的事情不会发生。对我来说,错误是间歇性的,并不是 100% 可靠地重现。

以上是关于为啥我通过 spawn() 创建的 Node 子进程挂起?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Python 多处理中将 start 方法从“fork”更改为“spawn”不再允许我运行我的工作?

为啥我的 iOS 应用无法使用 Node.js Agora Token Server 创建的令牌通过 AgoraRtcEngineKit 进行身份验证?

用spawn 来编写跨平台 Node.js命令

node js cli STDOUT STDERR 输出 exec 和 spawn 命令

为啥 erlang spawn 函数调用中出现语法错误 - “之前的语法错误:')'”?

获取 node.js 中所有嵌套子进程的标准输出