Skip to main content
Version: 4.x

Cluster adapter

How it works​

The Cluster adapter allows to use Socket.IO within a Node.js cluster.

Every packet that is sent to multiple clients (e.g. io.to("room1").emit() or socket.broadcast.emit()) is also sent to other workers via the IPC channel.

The source code of this adapter can be found here.

Installation​

npm install @socket.io/cluster-adapter

Usage​

With Node.js cluster​

const cluster = require("cluster");
const http = require("http");
const { Server } = require("socket.io");
const numCPUs = require("os").cpus().length;
const { setupMaster, setupWorker } = require("@socket.io/sticky");
const { createAdapter, setupPrimary } = require("@socket.io/cluster-adapter");

if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);

const httpServer = http.createServer();

// setup sticky sessions
setupMaster(httpServer, {
loadBalancingMethod: "least-connection",
});

// setup connections between the workers
setupPrimary();

// needed for packets containing buffers (you can ignore it if you only send plaintext objects)
// Node.js < 16.0.0
cluster.setupMaster({
serialization: "advanced",
});
// Node.js > 16.0.0
// cluster.setupPrimary({
// serialization: "advanced",
// });

httpServer.listen(3000);

for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}

cluster.on("exit", (worker) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork();
});
} else {
console.log(`Worker ${process.pid} started`);

const httpServer = http.createServer();
const io = new Server(httpServer);

// use the cluster adapter
io.adapter(createAdapter());

// setup connection with the primary process
setupWorker(io);

io.on("connection", (socket) => {
/* ... */
});
}

With PM2​

See the associated documentation.

With recluster​

cluster.js

const cluster = require("cluster");
const http = require("http");
const { setupMaster } = require("@socket.io/sticky");
const { setupPrimary } = require("@socket.io/cluster-adapter");
const recluster = require("recluster");
const path = require("path");

const httpServer = http.createServer();

// setup sticky sessions
setupMaster(httpServer, {
loadBalancingMethod: "least-connection",
});

// setup connections between the workers
setupPrimary();

// needed for packets containing buffers (you can ignore it if you only send plaintext objects)
// Node.js < 16.0.0
cluster.setupMaster({
serialization: "advanced",
});
// Node.js > 16.0.0
// cluster.setupPrimary({
// serialization: "advanced",
// });

httpServer.listen(3000);

const balancer = recluster(path.join(__dirname, "worker.js"));

balancer.run();

worker.js

const http = require("http");
const { Server } = require("socket.io");
const { setupWorker } = require("@socket.io/sticky");
const { createAdapter } = require("@socket.io/cluster-adapter");

const httpServer = http.createServer();
const io = new Server(httpServer);

// use the cluster adapter
io.adapter(createAdapter());

// setup connection with the primary process
setupWorker(io);

io.on("connection", (socket) => {
/* ... */
});

Options​

NameDescriptionDefault value
requestsTimeoutthe timeout for inter-server requests such as fetchSockets() or serverSideEmit() with ack5000