Stan Luo
Stan Luo

Reputation: 3889

Can't kill a specific worker in Node JS cluster

I'm using node + express as my web server, and has a cluster of 4 workers.

I tried several ways to deliberately kill a worker:

  1. process.exit() in a controller, and triggered using a browser action. Thought this is just for a single worker process, but turned out all workers were killed.

  2. Again in a controller, I let a worker send suicide announcement to the master:

    process.send('suicide');

and here goes my master process:

if (cluster.isMaster) {
  console.log(`Master cluster setting up ${numWorkers} workers...`);

  for (let i = 0; i < numWorkers; i++) {
    const worker = cluster.fork();
    worker.on('message', msg => {
      console.log(worker.process.pid + ' wants to suicide');
      worker.kill();
      process.kill(worker.process.pid);
    });
  }
}

It turned out, worker.kill() doesn't affect at all, and process.kill(worker.process.pid); killing all 4 workers again. Also, the console.log appeared 4 times which I don't understand. I used a browser to trigger some action that hence triggers the suicide announcement, shouldn't this be a single worker's behavior?

I'm also using WebSockets in the projects and keeps a connection, don't know if this matters. Any help is appreciated!

EDIT:

Thanks for @Mia I found the reason: when I put process.exit() in the else statement(when cluster.isWorker) it works fine, but when put in a specific controller, it turns out to affect all the workers. Don't know how to solve yet. Shouldn't the controller affect only one specific worker?

Upvotes: 0

Views: 3537

Answers (1)

Mia
Mia

Reputation: 184

I am sorry to write here, I am unable to comment due to my reputation. I have written like the following and it works fine. first clusters are created and open servers, whenever a cluster gets a request app.get("/"), 2 seconds later it exits by process.exit method. you can confirm that this works well by printing out remaining workers.

'use strict';

const cluster = require('cluster');
const os = require('os');

 if (cluster.isMaster) {
   const cpus = os.cpus().length;
   for (let i = 0; i < cpus; i++) {
     cluster.fork();
   }

  cluster.on('exit', (worker, code) => {

      console.log(`${worker.process.pid} is killed`);
      console.log("remaining wokers");
      const workers = Object.keys(cluster.workers);
      for(let worker of workers){
        console.log(cluster.workers[worker].process.pid);
      }

  });

} else {

  console.log("process id ",process.pid);

const express = require("express");
const app = express();
const path = require("path");
const fs = require("fs");
const http = require('http').Server(app);
const io = require('socket.io')(http);
const bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(express.static('public'));

app.get('/',function(req,res){
   console.log("connected via" , process.pid);
   setTimeout(()=>{
        process.exit();
   },2000)
   res.sendFile(path.join(__dirname+"/public/view/index.html"));
});

http.listen(3000);

}

----------------------------code separated into modules---------------

Root (server.js)

'use strict';

const cluster = require('cluster');
const os = require('os');

 if (cluster.isMaster) {
   const cpus = os.cpus().length;
   for (let i = 0; i < cpus; i++) {
     cluster.fork();
   }

  cluster.on('exit', (worker, code) => {

      console.log(`${worker.process.pid} is killed`);
      console.log("remaining wokers");
      const workers = Object.keys(cluster.workers);
      for(let worker of workers){
        console.log(cluster.workers[worker].process.pid);
      }

  });

} else {

  console.log("process id ",process.pid);

const express = require('./modules/express');
const http = require('http').Server(express);

http.listen(3000);

}

Express

const express = require("express");
const app = express();
const bodyParser = require('body-parser');
const route = require('../route');

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(express.static('public'));

route(app);

module.exports = app;

Route (index.js)

const HomeController = require('../controllers/HomeController');
module.exports = function(app){
  app.get('/',HomeController.renderIndex);
  app.get('/killProcess',HomeController.killProcess);
}

HomeController

const path = require('path');

exports.renderIndex = function(req,res){
  console.log("connected via" , process.pid);
  res.sendFile(path.join(__dirname+"/../public/view/index.html"));
}

exports.killProcess = function(req,res){

    res.write(`current process ${process.pid} is killed`);
    res.end();
    process.kill(process.pid);

}

Client side (browser)

  $("#kill").on("click",function(e){
        $.ajax({
            url:"/killProcess"
        }).success(function(data){
            console.log(data);
        })
    })

Upvotes: 3

Related Questions