Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep forked child process alive in node js

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);
});
like image 857
Fan Cheung Avatar asked Aug 21 '18 09:08

Fan Cheung


2 Answers

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 fds will be the default values if marked as null. For more info, refer stdio options docs

like image 75
yaswanth Avatar answered Sep 30 '22 04:09

yaswanth


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.

like image 23
Tom Boutell Avatar answered Sep 30 '22 04:09

Tom Boutell