14

Problem: We start pm2 in cluster mode, and pm2 starts as many processes as there are cpu cores, pm2 also tries to start as many node servers as there are cpu cores but the problem here is that it fails to start as many servers because they all try and start on the same port that is 3000, which already gets occupied by the first node server

We using nginx and proxy it to 3000 port.

we are using pm2 in cluster mode with the following configuration:

{
  "apps" : [{
    "script"    : "npm",
    "instances" : "max",
    "cwd":"/home/nginx/my-pwa" ,
    "args" : "run start:server:prod",
    "exec_mode" : "cluster",
    "wait_ready": true,
    "kill_timeout" : 4000,
    "watch" : true
  }]
}

run start:server:prod is our script to start the server

Our express server:

var app = require('../src/app');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

const http = require('http');
server = http.createServer(app);
server.listen(port));
server.on('error', onError);
server.on('listening', onListening);

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

process.on('message', function(msg) {
  if (msg == 'shutdown') {
    server.close();
    process.exit(0);  
  }
});

// Listening logic
function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
  console.log("Server started on ", bind);
  process.send('ready');
}

Please help, it's mission critical!

Gaurav Sobti
  • 569
  • 1
  • 4
  • 14

4 Answers4

22

The problem is that pm2 doesn't play well with npm. It is not able to start two node servers using npm script. The right way is to use node

My previous config:

{
  "apps" : [{
    "script"    : "npm",
    "instances" : "max",
    "cwd":"/home/nginx/my-pwa" ,
    "args" : "run start:server:prod",
    "exec_mode" : "cluster",
    "wait_ready": true,
    "kill_timeout" : 4000,
    "watch" : true
  }]
}

My new config:

{
  "apps" : [{
    "script"    : "./server/bin/www",
    "instances" : "max",
    "exec_mode" : "cluster",
    "cwd":"/home/nginx/my-pwa" ,
    "env": {"NODE_ENV" : "production"},
    "name" : "my-pwa"
  }]
}

As you can see that I am no longer using "script": "npm". ./server/bin/www contains my express server which pm2 will execute using node. Now pm2 is able to automatically handle clustering. So how's the output is supposed to look like now? It makes one god deamon which manages the worker server instances which are according to the number of your cpu cores. Output on our server: (It has 2 cores)

nginx     1363     1  0 05:20 ?        00:00:03 PM2 v2.10.1: God Daemon (/home/nginx/.pm2)
nginx     1373  1363  0 05:20 ?        00:00:09 node /home/nginx/my-pwa/server/bin/www
nginx     1374  1363  0 05:20 ?        00:00:09 node /home/nginx/my-pwa/server/bin/www

Also, now pm2 reload works fine. When I see logs on reload, pm2 starts new workers first and then shuts down the old workers.

Gaurav Sobti
  • 569
  • 1
  • 4
  • 14
  • shouldn't exec_mode be cluster_mode, not cluster? – buycanna.io Apr 11 '19 at 02:53
  • can you share your `./server/bin/www` script ?@Gaurav Sobti – Sumeet Kumar Feb 18 '20 at 18:03
  • i run for claster mode as show pm2 docs `pm2 /path/to/my/script.js -i number_of_cpu` example `pm2 /www/var/mysite/index.js -i 2`. it run 2 the instans. as show an docs ports it listen auto. it work for me. – romanown Jun 23 '22 at 21:48
  • for anyone using next.js use a [custom server configuration](https://nextjs.org/docs/advanced-features/custom-server) then follow the answer guide of @gaurav-sobti then just change the `script` to `server.js` configuration – Sauer Voussoir Dec 26 '22 at 19:12
5

For me changing the exec_mode to cluster_mode worked.

My ecosystem.config.js was changed to something like this

apps: [
  {
    script: 'server.js',
    instances: 'max',
    exec_mode: 'cluster_mode' // not 'fork' or 'cluster'
  }
]
palerdot
  • 7,416
  • 5
  • 41
  • 47
0

I don't think you can use pm2 cluster mode with npm scripts. First check if the process is actually in cluster mode using pm2 list. If it isn't, try modifying your configuration to call the node script directly instead of the calling npm script.

Miguel Calderón
  • 3,001
  • 1
  • 16
  • 18
0

My issue was that the script needed to be named ecosystem.config.js anything else wouldn't launch in cluster mode. it will launch in forked mode but the file name is necessary for any other config.

Kaki Master Of Time
  • 1,428
  • 1
  • 21
  • 39