Winner's Excogitations

A chronicle of the thoughts, learning experiences, ideas and actions of a tech junkie, .NET, JS and Mobile dev, aspiring entrepreneur, devout Christian and travel enthusiast.

Clustering in NodeJS

7 years ago ยท 3 minutes read

ocbqfgrgpiliepukqome

image credit: slideshare

The problem

I got started with NodeJS about three years ago. As I learnt to build enterprise-grade applications using the runtime, a major drawback I kept coming across in my research was the fact that NodeJS is aggressively single-threaded. What this meant was that no matter how many threads and cores your computer or server had, the NodeJS process was limited to the one thread on which it was running. This major limitation meant a NodeJS web application could not fully utilize the hardware on which it was running.

The solution

Enter the cluster module. The cluster module is one of the native (it comes bundled with the NodeJS runtime and doesn't require installing from NPM and what not) modules and it gives developers the ability to utilize the hardware available to their applications by allowing a single NodeJS web application utilize worker processes to help handle requests as well.

How to use

After coming across the cluster module, I felt integrating it into my application would require quite a number of changes to make the logic "process-aware" and "process-safe", that turned out to be a wrong assumption as the integration into an existing project was as painless as it could possibly be.

To get started, first require the cluster module as well as the os module (would explain why in a bit) in your server.js file or whatever JavaScript file your HTTP server creation logic is in like so:

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

Next, we want to add logic to determine what process our code is currently running in, i.e whether or not it is a master or worker process. We can do that by checking the isMaster boolean field on the cluster object.

...
if (cluster.isMaster) {
  // this is the master process
} else {
  // this is a worker process
}
...

Next, when the master process starts, we want to create worker processes based on the number of cores the current machine has. This is where the os module comes into play, the os module gives access to operating system level information and logic. We create worker/child process like so:

if (cluster.isMaster) {
  // this is the master process
  const cpuCount = os.cpus().length;

  for (let i = 0; i < cpuCount; i += 1) {
    cluster.fork();
  }
} else {
  // this is a worker process
}
...

Now we have successfully created our worker processes, next, we want to give the worker processes the logic they should execute when they are up. For this, we copy the logic we used to set up our web server into the else block. The logic to set up your web server would be different from mine but I'll use mine as an example. I am setting up an express web server which would provide a bunch of RESTful endpoints as well as serve some static files. This is what my web server logic looks like:

...
} else {
  const app = express();
  const router = express.Router();
  const port = process.env.PORT || 3000;

  app.use(morgan('dev'));
  app.use(cors());
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({
    extended: true
  }));

  routes.route(router);
  app.use('/v1/', router);

  app.use('/', express.static('public'), (req, res) => {
    res.status(200).sendFile(path.join(__dirname, '/public/index.html'));
  });

  app.listen(port, () => console.log(`Server started on ${port}`));
}
...

One last step, we need to know when one or more worker processes die or a killed off and replace them. To do that, we listen for the exit event on the cluster and carry out our revival efforts there.

...
cluster.on('exit', function (worker) {
  console.log('Worker %d died :(', worker.id);
  cluster.fork();
});

With that last step, we are good to go. Your web server should be ready to handle a bunch more requests right off the bat. The final, complete server.js file can be found here

Cheers.

Share on:
[HOW TO] Deploy an ASP.NET Core SPA app to Heroku
A short guide on deploying an ASP.NET Core SPA (Angular or React) web application to Heroku
[HOW TO] Install Siege Http On A Mac
A step by step procedure for installing JoeDog's Siege HTTP testing utility on a Mac computer
Winner-Timothy Bolorunduro
Winner-Timothy Bolorunduro is a senior .NET developer with over 6 years experience helping organizations and individuals build compelling, stable and scalable web applications. Having spent the last three years in a fast-paced startup environment working remotely, he understands what goes into being part of a team that produces value for clients.

Comments