Node.js Cluster IPC: Setup and Communication
Scaling Node.js applications often requires utilizing multiple CPU
cores through clustering. This article provides a straightforward guide
on how to set up a Node.js cluster using the native cluster
module and facilitate seamless communication between the primary
(master) process and worker processes using Inter-Process Communication
(IPC).
Understanding Node.js Clustering and IPC
By default, Node.js runs in a single-threaded event loop. To leverage
multi-core systems, the native cluster module allows you to
spawn a network of worker processes that share the same server
ports.
Because these processes run in separate operating system instances, they do not share memory. To allow them to coordinate, Node.js establishes an Inter-Process Communication (IPC) channel automatically when workers are forked. This channel permits the passing of messages back and forth using serialization.
Step-by-Step Implementation
Below is a complete, self-contained example demonstrating how to initialize a primary process, fork worker processes, and exchange data bidirectionally.
import cluster from 'node:cluster';
import { cpus } from 'node:os';
import process from 'node:process';
if (cluster.isPrimary) {
console.log(`Primary process ${process.pid} is running.`);
// Fork workers based on available CPU cores
const numCPUs = cpus().length;
for (let i = 0; i < numCPUs; i++) {
const worker = cluster.fork();
// 1. Listen for messages sent from this specific worker
worker.on('message', (msg) => {
console.log(`Primary received message from Worker ${worker.id}:`, msg);
// 2. Reply back to the worker
worker.send({
reply: `Acknowledged message ${msg.id}`,
status: 'success'
});
});
}
// Handle worker exits
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} terminated. Code: ${code}, Signal: ${signal}`);
});
} else {
console.log(`Worker ${process.pid} started with ID: ${cluster.worker.id}`);
// 3. Send an initial message to the primary process
process.send({
id: cluster.worker.id,
text: 'Hello from the worker process!'
});
// 4. Listen for messages sent from the primary process
process.on('message', (msg) => {
console.log(`Worker ${cluster.worker.id} received message from Primary:`, msg);
});
}How the IPC Flow Works
The messaging pipeline relies on distinct methods depending on whether you are writing code for the primary process or the worker processes:
1. Sending Messages
- From Primary to Worker: The primary process uses
the reference to the worker object returned by
cluster.fork(). You send messages to a specific worker usingworker.send(message). - From Worker to Primary: Worker processes do not
have direct references to other workers or the primary process object.
Instead, they use the global
process.send(message)method, which routes the message directly to the primary process.
2. Receiving Messages
- In the Primary Process: The primary process
registers an event listener on each individual worker object:
worker.on('message', callback). - In the Worker Process: The worker process listens
globally on its own process object:
process.on('message', callback).
3. Data Format
The payload passed through the send() method can be any
serializable JavaScript object, array, string, number, or boolean.
Node.js automatically stringifies the object to JSON internally and
parses it upon arrival.