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

  1. npm install @socket.io/cluster-adapter

Usage

With Node.js cluster

  1. 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

  1. 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

  1. 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

Caught a mistake? Edit this page on GitHub