I want to create a rabbitmq cli running like foreverjs with node. It can spawn child_process and keep it running in the background and can communicate with child_process at any time. The problem I am facing is when main cli program exit the child_process seems to stop running as well, I tried to fork with detached:true and .unref() it doesn't work. How do i run a child process in the background even after the parent caller process exited?
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 if it is up and running, 'i' should keep incrementing
var i=0;
i++;
if (process.send) {
process.send("Hello"+i);
}
process.on('message', message => {
console.log('message from parent:', message);
});
I think fork
doesn't have a detached
option. Refer node docs for fork.
If you use spawn
, the child keeps running even if the parent exits. I have modified your code a bit to use 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);
I think when you use fork, an IPC channel
is established between the parent and the child process. You could try disconnecting the IPC channel
gracefully before exiting the parent process. I'll try it out and update the answer if it works.
Update:
I have updated cli.js
and rabbit.js
to get it working as asked. The trick is to use ipc
file descriptor in stdio
options. That way you can communicate with the parent from the child. The first three fd
s will be the default values if marked as null
. For more info, refer stdio options docs
An old question, but for those picking up where I am today: fork
does have a detached
option. However it also opens an IPC channel which has to be explicitly closed with disconnect()
as well if you want to break the relationship between the parent and the child.
In my case it was advantageous to use the channel until I had confirmation that the child process was ready to do its job, and then disconnect it:
// 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();
This allows my parent process to exit without killing the background process or being kept alive by a reference to it.
If you do establish any handle.on(...)
handlers, it's a good idea to disconnect them with handle.off(...)
as well when you are through with them. I used a handle.on('message', (data) => { ... })
handler to allow the child to tell the parent when it was ready for its duties after doing some async startup work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With