Startup Sequence of Nodejs Apps using PM2
Asked Answered
T

2

5

I am using the command pm2 start apps.json to start multiple apps in a single command. These apps are defined in apps.json:

{
  "apps": [
    {
      "name": "foo",
      "script": "./foo.js",
    },
    {
      "name": "bar",
      "script": "./bar.js",
    },
    {
      "name": "baz",
      "script": "./baz.js",
    }
  ]
}

Question: Is it possible to define the startup sequence, such that foo.js has to finish starting first before bar.js and baz.js can start?

For example, foo.js can perform a graceful start, running process.send('ready') to change its pm2 status to online. Only then will bar.js and baz.js be started by pm2. This will be similar to Docker Compose's depend_on parameter.

Tenantry answered 25/6, 2020 at 4:48 Comment(1)
there are some questions that affects possible approaches: 1. are their startup sequence sync. or async.; 2. do they expose any ports; 3. are they singleton, i.e. is it safe to assume only 1 of each will be running on a single system.Chrismatory
A
4

No such thing can be done via the configuration file only, but PM2 has a programmatic api which allows you to perform IPC (Inter-Process communication).

The following methods are the ones to work with :

  • pm2.list To list the processes that are running and get their names / IDs
  • pm2.launchBus For the processes that will receive information and react in consequence
  • pm2.sendDataToProcessId For sending informations to another process

This way you can run multiple scripts and make one wait for another. Once a script recieve a message on the message bus, it can start a process with pm2.start

Here's a piece of PSEUDO-CODE to illustrate my point :

const pm2 = require('pm2');

pm2.connect(() => {
  pm2.list(function(err, processes) {
    const fooProcess = processes.find(p => p.name == 'foo');

    pm2.launchBus((err, bus) => {
      bus.on('process:msg', packet => {
        if (packet.startBar === true) {
          pm.start({ script: 'bar.js' }, (err, apps) => { ... })
        }
      });
      bus.on('error', console.error);
    });
  });
});

In another script, you would have the following :

pm2.sendDataToProcessId(barProcessID, {
  data : { startBar : true },
  topic: 'process:msg'
}, (err, res) => console.log(err, res));

Best regards

Afroasiatic answered 28/9, 2020 at 13:54 Comment(0)
S
4

A little hack, you can write: "start": "pm2 start server.js && pm2 start server1.js" inside package.json. If you'd run it as npm start, it'll run the start script, similarly, you can create the script to stop it.

If not then you can also use child_process [it comes by default with nodejs] to run commands from inside your script by using childProcess.exec('pm2 start server.js && pm2 start server1.js');

Syndesis answered 28/9, 2020 at 22:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.