Module 6 / Live updates / Reconnection and missed-message recovery

Lesson9 minModule 6 · lesson 7 of 9

Reconnection and missed-message recovery

What happens after the signal comes back.

A rider walks through a subway tunnel for 8 minutes. Their phone loses its WebSocket, and during that time 14 messages arrive in their group chat. When the signal returns, pushing is not enough: the connection that would have delivered those messages is gone. The app must notice the disconnect, reconnect, and ask 'what did I miss?'.

The robust pattern has three parts. First, reconnect with backoff: wait 1 second, then 2, 4, 8, up to a cap of say 30 seconds, and add random jitter to each wait. Second, remember the last sequence number seen per conversation. Third, on reconnect, send those numbers so the server can replay everything newer. This turns a lossy push channel into a reliable system, because the stored log, not the live connection, is the source of truth.

async function reconnect() {
  let delay = 1000;
  while (true) {
    try {
      const ws = await connect();
      // tell the server where we stopped, per conversation
      ws.send(JSON.stringify({ type: "resume", cursors: lastSeenSeqByChat }));
      return ws;
    } catch {
      await sleep(delay + Math.random() * 500); // jitter
      delay = Math.min(delay * 2, 30000);        // exponential, capped
    }
  }
}
Reconnect with exponential backoff, jitter and a resume cursor.
ClientGatewayMessage logresume withlast seqread after seqmissedmessages, thenlive
Resume fetches the gap from the durable log.

Why the jitter? Imagine a gateway with 50,000 connections crashes. Without jitter, all 50,000 clients retry in lockstep, and the same instant spike hits the remaining servers and the log. Each reconnect also triggers a catch-up read. Spread the retries across several seconds and the load becomes a manageable ramp instead of a wall.

Reconnect surge

Press play: 50,000 clients reconnect within three seconds and each needs a catch-up fetch. Look at the backlog. Then spread the same 50,000 over six seconds and see how the peak shrinks.

Grey = messages arriving that second. Amber = messages waiting in the queue.

Press Step to begin.

Catch-up capacity is 10,000 per second here, so the same 50,000 reconnects with jitter spread over six seconds (roughly 8,300 each second) would never build a backlog at all. Also protect the catch-up path: if someone has been offline for a week, do not replay thousands of messages. Send the latest page plus a count of unread items and let the user load more.

Question 1

Why add random jitter to reconnect delays?

Question 2

What must a client remember to recover missed messages?

Your turn

A user was offline for three days and has 2,500 unread messages across 40 chats. Design what the app shows and fetches on reconnect.

Stuck? Avoid loading everything at once.

What to remember

  1. Reconnect with exponential backoff and jitter.

  2. Keep a per-conversation last-seen cursor and resume from it.

  3. The stored log is the truth; pushes are an optimization.

  4. Limit catch-up size so long absences stay cheap.