Benny Code
Benny Code

Reputation: 54782

How to notify a child process from forever monitor on SIGINT in parent process?

I am using forever-monitor on Windows where child processes are detached by default.

In my application I have a monitor.js file which monitors a server.js file and I want to be able to notify server.js when I close my application by exiting monitor.js (hitting Ctrl + C on the command-line).

Here is my demo code:

monitor.js

const path = require('path');
const forever = require('forever-monitor');

let child;

function exit() {
  console.error('Received exit signal on main process.');
  if (child) {
    // TODO: Here I want to notify the "child", so that it can gracefully shutdown my server
    child.stop();
  }
  process.exit(0);
}

['SIGINT', 'SIGKILL', 'SIGTERM'].forEach(signal => process.on(signal, exit));

child = new forever.Monitor(path.join(__dirname, 'server.js'));
child.start();

server.js

const express = require('express');

const app = express();
const port = process.env.PORT || 8080;

let server;

function stopServer() {
  if (server) {
    console.log('Shutting down server...');
    server.close();
  }
}

app.get('/', (request, response) => response.send('Hello'));
server = app.listen(port, () => console.log(`Server is running on port "${port}".`));

How can I call stopServer in server.js when monitor.js receives a SIGINT?

Upvotes: 2

Views: 790

Answers (1)

Benny Code
Benny Code

Reputation: 54782

The secret sauce is to start the child process with option "fork".

Using the "fork" option makes it possible to send messages from the parent process to the child process by calling child.send. This gives the ability to listen in the child process on a custom close message from the parent process, so that the child can stop the server and exit with custom exit code 1337.

When the parent/main process realizes that the child process has been closed with code 1337 , then the main process also shuts down.

Here is my solution:

monitor.js

const path = require('path');
const forever = require('forever-monitor');

let child;

function exit(signal) {
  console.error(`Received "${signal}" signal on main process.`);
  if (child) {
    child.send({action: 'close'});
  }
}

['SIGINT', 'SIGKILL', 'SIGTERM'].forEach(signal => process.on(signal, () => exit(signal)));

process.on('exit', (code) => console.log(`Stopped main process with code "${code}".`));

const options = {fork: true};

child = new forever.Monitor(path.join(__dirname, 'server.js'), options);

child.on('exit:code', (code) => {
  if (code === 1337) {
    if (child) {
      child.stop();
      console.log('Successfully stopped child process.');
    }
    console.log('Stopping main process ...');
    process.exit(0);
  }
});

child.start();

server.js

const express = require('express');

const app = express();
const port = process.env.PORT || 8080;

let server;

if (process.send) {
  process.on('message', function (message) {
    console.log(`Received "${message.action}" message from main process.`);
    if (message.action === 'close') {
      stopServer();
    }
  });
}

function stopServer() {
  if (server) {
    console.log('Stopping server in child process ...');
    server.close(() => {
      console.log('Stopped server in child process.');
      process.exit(1337);
    });
  }
}

app.get('/', (request, response) => response.send('Hello'));
server = app.listen(port, () => console.log(`Server is running on port "${port}".`));

Upvotes: 2

Related Questions