Kunal Chaudhari
Open to work Let's talk

(Real-Time) Jul 2026 — Present · Webbrains Technologies

Study-Flow

Live study rooms that stay in sync, however many people join.

Virtual study rooms with live focus timers, streaks, badges and leaderboards. Everyone in a room sees the same thing at the same moment — and it stays that way as more people join.

Role
Full Stack Developer
Focus
Real-time layer, queues, schedules
Status
Live and maintained

(01) In numbers

  • 79REST endpoints

    Sessions, groups, tasks and scoring

  • 15Mongoose models

    The durable half of a mostly live product

  • 12Scheduled jobs

    Node-Cron: reports, reminders and summaries

  • 2+Node processes

    Fanned out over Redis, not pinned to one box

(02) Under the hood

A count that has to be the same number on every process

  1. 01 · CLIENT

    Socket connection

    A participant joins a room and expects the count to be right — not eventually right, and not right only for whoever landed on the same server.

  2. 02 · EDGE

    Nginx upgrade

    The proxy passes the connection through as a WebSocket rather than terminating it as a request.

  3. 03 · SOCKET

    Socket.IO server

    One of several Node processes accepts the connection. Which one it was should stop mattering immediately after this.

  4. 04 · ADAPTER

    Redis pub/sub

    The adapter carries emits between processes. A room is a room across the whole cluster, not per instance.

  5. 05 · API

    79 endpoints

    The REST surface behind the live layer: sessions, groups, tasks and scores, over 15 Mongoose models.

  6. 06 · QUEUE

    BullMQ workers

    Anything slow is handed to a queue instead of being done on the socket's thread. The live layer stays live.

  7. 07 · CRON

    Twelve schedules

    Node-Cron jobs for the work that has a time rather than a trigger — summaries, reminders, and the periodic tidying.

(03) The story

01 — The Problem

Correct on one process is not correct

A participant count kept in memory is right until there are two servers, and then it is two different numbers. Leaderboards have the same shape of problem: everybody in the room has to be looking at the same figure.

  • Live counts and leaderboards shared across every connection.
  • More than one Node process, by design rather than by accident.
  • Slow work that must not block the real-time path.

02 — What I Built

Redis under the sockets, queues beside them

Socket.IO runs over a Redis adapter so an emit reaches every process. The expensive work moved off the socket path into BullMQ workers, and anything that runs on a clock moved into Node-Cron.

  • Socket.IO over a Redis adapter for rooms and emits that span processes.
  • 79 REST endpoints across 15 Mongoose models behind the live layer.
  • BullMQ queues for work that must not run inline.
  • Twelve Node-Cron schedules for periodic reports and reminders.

03 — What Changed

It scales sideways

Adding a process adds capacity instead of adding a version of the truth. A participant sees the same count as everyone else in the room, regardless of which instance answered them.

  • Rooms, counts and leaderboards agree across instances.
  • Capacity is a process count rather than a rewrite.
  • Slow jobs queue instead of stalling a connection.

(04) Architecture

The live layer, and everything holding it up

  1. 01

    Clients

    Browser sessions holding a socket open as well as making requests.

  2. 02

    Edge

    Nginx passing WebSocket upgrades through to the Node processes.

  3. 03

    Real-time

    Socket.IO over a Redis adapter: rooms that span processes.

  4. 04

    API

    Express modules for sessions, groups, tasks and scoring.

  5. 05

    Jobs

    BullMQ workers, and twelve Node-Cron schedules.

  6. 06

    Data

    15 Mongoose models, with Redis carrying the state that is only ever live.

(05) Decisions

Why it is built this way

  1. (01)

    Real-time state does not belong in a process

    The moment there are two instances, in-memory room state is two answers to one question. Redis holds it so the processes stay interchangeable.

  2. (02)

    Queues protect the live path

    Work that takes a while goes to BullMQ. The socket layer's job is to be quick, and the most reliable way to keep it quick is to give it less to do.

  3. (03)

    Scheduled work is its own tier

    Twelve cron jobs run the periodic work, rather than it piggybacking on whichever request happens to arrive at the right moment.

(06) Built with

What it runs on

A live layer that does not care which process answered.

For the technically curiousSocket.IO over a Redis adapter, so real-time scales past one Node process. Live participant counts and leaderboards that had to stay correct while running on more than one Node process. Socket.IO over a Redis adapter now scales the real-time layer horizontally, with the heavy work moved into BullMQ queues and twelve Node-Cron jobs.

Node.jsExpressSocket.IORedisBullMQNode-CronMongoDBMongooseReactDockerNginxPM2