如何在节点 js 中保持分叉子进程处于活动状态



我想创建一个像 foreverjs 一样使用 node 运行的 rabbitmq cli。它可以生成child_process并保持其在后台运行,并可以随时与child_process通信。我面临的问题是,当主cli程序退出时,child_process似乎也停止运行,我试图使用detached:true和.unref((分叉它不起作用。即使在父调用方进程退出后,如何在后台运行子进程?

CLI .js - 父级

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()

兔子.js - 儿童 如果它已启动并运行,则"i"应继续递增

var i=0;
i++;
if (process.send) {
process.send("Hello"+i);
}
process.on('message', message => {
console.log('message from parent:', message);
});

我认为fork没有detached选择。参考节点文档进行分叉。

如果使用spawn,即使父项退出,子项也会继续运行。我已经对您的代码进行了一些修改以使用spawn.

命令行.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);
});

兔子.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 时,会在父进程和子进程之间建立IPC channel。您可以尝试在退出父进程之前正常断开IPC channel的连接。我会尝试一下,如果它有效,我会更新答案。

更新:

我已经更新了cli.jsrabbit.js,以使其按要求工作。诀窍是在stdio选项中使用ipc文件描述符。这样您就可以从孩子那里与父母沟通。如果标记为null,则前三个fd将是默认值。有关更多信息,请参阅 stdio 选项文档

一个老问题,但对于那些了解我今天的人:fork确实有一个detached选择。但是,它还会打开一个IPC通道,如果您想打破父级和子级之间的关系,则必须用disconnect()明确关闭该通道。

就我而言,在我确认子进程已准备好完成其工作之前使用该通道是有利的,然后断开连接:

// 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(); 

这允许我的父进程退出,而不会终止后台进程或通过引用它保持活动状态。

如果您确实建立了任何handle.on(...)处理程序,最好在完成它们时也将它们与handle.off(...)断开连接。我使用了一个handle.on('message', (data) => { ... })处理程序,允许孩子在完成一些异步启动工作后告诉父级何时准备好履行职责。

fork 和 spawn 都有分离选项。

但是,当父进程退出时,子进程可能希望写入初始标准输出(通过"process.stdout.write","console.log"等(。 但是,此标准输出可能不再可用(因为父进程已死亡(,从而在子进程中引发一些异常(例如,管道损坏(。这些异常也可能导致子项意外失败。

如果我们允许子级写入某些始终可用的输出(例如文件(,它将不再失败,因为它仍然可以将信息写入有效实体。

/**
* 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);

相关内容

最新更新