Scaling Express.js application using node.js modules


Scaling Express.js application using node.js modules
14
Oct

Worker processes in clustered apps can crash without affecting the rest of the processes. Aside from the performance benefits, another reason to create a cluster of app processes is to isolate failures. Consistently report the event and use the cluster.fork() to start a new worker process whenever a worker process crashes.

 

Let's create a new directory, call it node-cluster-app or something like that. Then open CLI and run the command:

npm init

Fill all the information in cli, then install express package, run command:

npm install express

 

This is a basic app.js file:

const express = require('express');
const app = express();


app.get('/', (request, response, nextHandler) => {
  response.send('Hello World!');
  console.log(`Served by worker with process id (PID) ${process.pid}.`);
});

const server = require('http').createServer(app);

server.on('listening', () => {
  console.log("App listening on port 3000");
})
server.listen(3000);

 

Now we can run it via

node ./app.js

And we should get an output like:

App listening or port 3000

And when you navigate to http://localhost:3000

or run command
curl localhost:3000/

We should see "Hello World!" as a response and the console will show:

Served by worker with process id (PID) XXXX.

 

The next step is creating a cluster.js file in same directory as the preceding step.

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

if (cluster.isMaster) {
    // Get number of CPU core
    const cpus = os.cpus().length;

    console.log(`Number of Cluster: ${cpus}`)
    for (let i = 0; i < cpus; i++) {
        cluster.fork();
    }
    // set console's directory where we can see output from workers
    console.dir(cluster.workers, {depth: 0});

    // initialize our CLI 
    process.stdin.on('data', (data) => {
        initControlCommands(data);
    })

    cluster.on('exit', (worker, code) => {
        // Good exit code is 0 :))
        // exitedAfterDisconnect ensures that it is not killed by master cluster or manually
        // if we kill it via .kill or .disconnect it will be set to true
        // \x1b[XXm represents a color, and [0m represent the end of this 
        //color in the console ( 0m sets it to white again )
        if (code !== 0 && !worker.exitedAfterDisconnect) {
            console.log(`\x1b[34mWorker ${worker.process.pid} crashed.\nStarting a new worker...\n\x1b[0m`);
            const nw = cluster.fork();
            console.log(`\x1b[32mWorker ${nw.process.pid} will replace him \x1b[0m`);
        }
    });

    console.log(`Master PID: ${process.pid}`)
} else {
    // how funny, this is all needed for workers to start
     require('./app.js');
}

 

Now we can run our application as a cluster by typing:

node cluster.js

output should like this:

Number of Cluster: 8
{
  '1': [Worker],
  '2': [Worker],
  '3': [Worker],
  '4': [Worker],
  '5': [Worker],
  '6': [Worker],
  '7': [Worker],
  '8': [Worker]
}
Master PID: 17780
App listening on port 3000
App listening on port 3000
App listening on port 3000
App listening on port 3000
App listening on port 3000
App listening on port 3000
App listening on port 3000
App listening on port 3000
Worker 17788 crashed.
Starting a new worker...
Worker 17846 will replace him
App listening on port 3000
Worker 17794 crashed.
Starting a new worker...

Worker 17856 will replace him 
Worker 17804 crashed.
Starting a new worker...

Worker 17864 will replace him
App listening on port 3000
App listening on port 3000

 

The app.js is now running as cluster. This is how we can increase our node.js and express.js app performance. 


Login   To Comment & Like

Comments