如何在节点 js 中保持分叉 child 进程存活
How to keep forked child process alive in node js
我想用 node 创建一个 rabbitmq cli 运行ning 就像 foreverjs。它可以生成 child_process 并在后台保持 运行ning 并且可以随时与 child_process 通信。我面临的问题是当主 cli 程序退出时,child_process 似乎也停止了 运行ning,我尝试用 detached:true 和 .unref() 进行分叉,但它不起作用。即使在 parent 调用进程退出后,我如何在后台 运行 一个 child 进程?
cli.js - parent
const { fork, spawn } = require('child_process');
const options = {
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
slient:true,
detached:true
};
child = fork('./rabbit.js', [], options)
child.on('message', message => {
console.log('message from child:', message);
child.send('Hi');
// exit parent
process.exit(0);
});
child.unref()
rabbit.js - child
如果启动并且 运行ning,'i' 应该继续递增
var i=0;
i++;
if (process.send) {
process.send("Hello"+i);
}
process.on('message', message => {
console.log('message from parent:', message);
});
我认为 fork
没有 detached
选项。参考 node docs for fork.
如果您使用 spawn
,即使 parent 退出,child 也会保留 运行。我已经稍微修改了您的代码以使用 spawn
.
cli.js
const { fork, spawn } = require('child_process');
const options = {
slient:true,
detached:true,
stdio: [null, null, null, 'ipc']
};
child = spawn('node', ['rabbit.js'], options);
child.on('message', (data) => {
console.log(data);
child.unref();
process.exit(0);
});
rabbit.js
var i=0;
i++;
process.send(i);
// this can be a http server or a connection to rabbitmq queue. Using setInterval for simplicity
setInterval(() => {
console.log('yash');
}, 1000);
我认为当你使用 fork 时,在 parent 和 child 进程之间建立了一个 IPC channel
。您可以尝试在退出 parent 进程之前优雅地断开 IPC channel
的连接。我会尝试一下,如果有效,我会更新答案。
更新:
我已经更新了 cli.js
和 rabbit.js
以使其按要求工作。诀窍是在 stdio
选项中使用 ipc
文件描述符。这样您就可以从 child 与 parent 进行通信。如果标记为 null
,前三个 fd
将是默认值。有关详细信息,请参阅 stdio options docs
一个老问题,但对于那些了解我今天所处位置的人来说:fork
确实有一个 detached
选项。但是,如果您想打破 parent 和 child.
之间的关系,它还会打开一个必须用 disconnect()
显式关闭的 IPC 通道
在我的例子中,在我确认 child 进程已准备好执行其工作之前使用通道是有利的,然后断开它:
// Run in background
const handle = cp.fork('./service/app.js', {
detached: true,
stdio: 'ignore'
});
// Whenever you are ready to stop receiving IPC messages
// from the child
handle.unref();
handle.disconnect();
这允许我的 parent 进程退出而不会终止后台进程或通过引用它来保持活动状态。
如果您确实建立了任何 handle.on(...)
处理程序,最好也将它们与 handle.off(...)
断开连接,当您使用完它们时也是如此。我使用 handle.on('message', (data) => { ... })
处理程序允许 child 在完成一些异步启动工作后通知 parent 它何时准备好履行其职责。
fork 和 spawn 都有 detached 选项。
但是,当parent进程退出时,child可能想要写入初始标准输出(通过“process.stdout.write”、“console.log”等)。
但是,此标准输出可能不再可用(因为 parent 已死),从而在 child 进程中引发一些异常(例如,管道损坏)。这些异常可能会导致 child 也意外失败。
如果我们允许child写入某些始终可用的输出(例如文件),它将不再失败,因为它仍然可以将信息写入有效实体。
/**
* This code apart from the comments is available on the Node website
*/
// We use fork, but spawn should also work
const {fork} = require('child_process');
let out = fs.openSync("/path/to/outfile", "a");
let err = fs.openSync("/path/to/errfile", "a");
const child = fork(jsScriptPath, ["--some", "arg"], {
detached: true,
stdio: ["pipe", out, err, "ipc"], // => Ask the child to redirect its standard output and error messages to some files
// silent is overriden by stdio
});
// SetTimeout here is only for illustration. You will want to use more valid code
setTimeout( () => {
child.unref();
process.exit(0);
}, 1000);
我想用 node 创建一个 rabbitmq cli 运行ning 就像 foreverjs。它可以生成 child_process 并在后台保持 运行ning 并且可以随时与 child_process 通信。我面临的问题是当主 cli 程序退出时,child_process 似乎也停止了 运行ning,我尝试用 detached:true 和 .unref() 进行分叉,但它不起作用。即使在 parent 调用进程退出后,我如何在后台 运行 一个 child 进程?
cli.js - parent
const { fork, spawn } = require('child_process');
const options = {
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
slient:true,
detached:true
};
child = fork('./rabbit.js', [], options)
child.on('message', message => {
console.log('message from child:', message);
child.send('Hi');
// exit parent
process.exit(0);
});
child.unref()
rabbit.js - child 如果启动并且 运行ning,'i' 应该继续递增
var i=0;
i++;
if (process.send) {
process.send("Hello"+i);
}
process.on('message', message => {
console.log('message from parent:', message);
});
我认为 fork
没有 detached
选项。参考 node docs for fork.
如果您使用 spawn
,即使 parent 退出,child 也会保留 运行。我已经稍微修改了您的代码以使用 spawn
.
cli.js
const { fork, spawn } = require('child_process');
const options = {
slient:true,
detached:true,
stdio: [null, null, null, 'ipc']
};
child = spawn('node', ['rabbit.js'], options);
child.on('message', (data) => {
console.log(data);
child.unref();
process.exit(0);
});
rabbit.js
var i=0;
i++;
process.send(i);
// this can be a http server or a connection to rabbitmq queue. Using setInterval for simplicity
setInterval(() => {
console.log('yash');
}, 1000);
我认为当你使用 fork 时,在 parent 和 child 进程之间建立了一个 IPC channel
。您可以尝试在退出 parent 进程之前优雅地断开 IPC channel
的连接。我会尝试一下,如果有效,我会更新答案。
更新:
我已经更新了 cli.js
和 rabbit.js
以使其按要求工作。诀窍是在 stdio
选项中使用 ipc
文件描述符。这样您就可以从 child 与 parent 进行通信。如果标记为 null
,前三个 fd
将是默认值。有关详细信息,请参阅 stdio options docs
一个老问题,但对于那些了解我今天所处位置的人来说:fork
确实有一个 detached
选项。但是,如果您想打破 parent 和 child.
disconnect()
显式关闭的 IPC 通道
在我的例子中,在我确认 child 进程已准备好执行其工作之前使用通道是有利的,然后断开它:
// Run in background
const handle = cp.fork('./service/app.js', {
detached: true,
stdio: 'ignore'
});
// Whenever you are ready to stop receiving IPC messages
// from the child
handle.unref();
handle.disconnect();
这允许我的 parent 进程退出而不会终止后台进程或通过引用它来保持活动状态。
如果您确实建立了任何 handle.on(...)
处理程序,最好也将它们与 handle.off(...)
断开连接,当您使用完它们时也是如此。我使用 handle.on('message', (data) => { ... })
处理程序允许 child 在完成一些异步启动工作后通知 parent 它何时准备好履行其职责。
fork 和 spawn 都有 detached 选项。
但是,当parent进程退出时,child可能想要写入初始标准输出(通过“process.stdout.write”、“console.log”等)。 但是,此标准输出可能不再可用(因为 parent 已死),从而在 child 进程中引发一些异常(例如,管道损坏)。这些异常可能会导致 child 也意外失败。
如果我们允许child写入某些始终可用的输出(例如文件),它将不再失败,因为它仍然可以将信息写入有效实体。
/**
* This code apart from the comments is available on the Node website
*/
// We use fork, but spawn should also work
const {fork} = require('child_process');
let out = fs.openSync("/path/to/outfile", "a");
let err = fs.openSync("/path/to/errfile", "a");
const child = fork(jsScriptPath, ["--some", "arg"], {
detached: true,
stdio: ["pipe", out, err, "ipc"], // => Ask the child to redirect its standard output and error messages to some files
// silent is overriden by stdio
});
// SetTimeout here is only for illustration. You will want to use more valid code
setTimeout( () => {
child.unref();
process.exit(0);
}, 1000);