当将stdin管道传递给子进程时,NodeJS进程永远不会结束



我使用spawn来创建子进程和管道数据:

child process  |  parent process (main)
---------------------------------------
stdout      ----->       process.stdout
stderr      ----->       process.stderr
stdin       <-----        process.stdin

问题是,当process.stdin管道到子进程stdin时,当子进程结束时,主进程没有结束。

代码看起来像这样(不是一个很好的例子,因为ps不使用stdin数据,我猜):

var Spawn = require("child_process").spawn;
var ps = Spawn("ps");
process.stdin.pipe(ps.stdin);
ps.stdout.pipe(process.stdout);
ps.stderr.pipe(process.stderr);

如果我删除process.stdin.pipe(ps.stdin)行,主进程结束,但stdin数据不再是管道。

为什么ps子进程结束时主进程没有结束?我该如何解决这个问题?

一个丑陋的解决方案是:

ps.on("close", process.exit.bind(process));

我不喜欢这个,因为我真的不想强迫主进程关闭,但我想自然地关闭(例如让setTimeout(function(){}, 1000)等待1000ms,然后进程结束)。

我不知道这是Node中的错误还是预期的行为,但是有几个解决方法,其中一个可能适合您。

如果当前进程恰好在子进程结束时结束,您可以简单地为exit添加一个处理程序,如下所示:

const fail = err => { throw err }
ps.on("exit", (code, signal) => code !== null ? process.exit(code) : signal !== null ? process.kill(process.pid, signal) : fail("Impossible situation, child process neither exited nor was killed"))

这将绕过我们的问题,stdin流坐在那里阻止一切。

如果你需要在当前进程中做更多的事情,而不仅仅是运行这个子进程,这种方法可能是不可接受的。当你意识到当前流程应该做的所有工作都已经完成时,你可以做的是destroy process.stdin。例如,如果您只希望运行ps,则可以添加:

ps.on("exit", (...) => {
  ...
  process.stdin.destroy()
})

,这将有相同的效果。如果在ps死后需要做更多的工作,可以将相同的事情放在其他适当的事件处理程序中。

最新更新