Real-Time APIs · Scaling Real-Time Systems

Slow Clients and Backpressure

Protect servers from consumers that can't keep up.

A client on a slow network can't drain messages fast enough, so the server's send buffer grows. Without limits, a few slow clients exhaust memory. Monitor per-connection buffered bytes (bufferedAmount/socket write buffer), apply policies: drop non-critical updates (send only the latest state — conflation), disconnect clients exceeding limits (they reconnect and resync), and keep messages small. For high-frequency data (prices, positions), conflate to the latest value per key.

Slow consumer policies

Policy Use for Effect
Unbounded buffering Never Memory exhaustion
Drop non-critical Typing, cursor positions Client sees fewer updates
Conflate (latest per key) Prices, positions, counters Always current, fewer messages
Disconnect + resync Critical streams Client reloads state

TypeScript (ws)

const MAX_BUFFER = 1 * 1024 * 1024;   // 1 MB
function sendOrDrop(ws: WebSocket, msg: Message) {
  if (ws.bufferedAmount > MAX_BUFFER) {
    if (msg.critical) return ws.close(4008, "slow consumer");   // client will reconnect and resync
    return metrics.increment("ws.dropped");                    // drop non-critical update
  }
  ws.send(JSON.stringify(msg));
}

// Conflation: keep only the latest price per symbol and flush every 100 ms
const latest = new Map<string, Price>();
setInterval(() => { for (const [, p] of latest) broadcast(p); latest.clear(); }, 100);

Common pitfalls

  • Ignoring bufferedAmount.
  • Sending every intermediate value of fast-changing data.
  • Large JSON messages for frequent updates.

Key points

  • Bound per-connection buffers
  • Conflate high-frequency data
  • Disconnect and resync when needed

Further reading: MDN: WebSocket.bufferedAmount

Practice questions

What is conflation in real-time systems?

Answer

Replacing queued updates for the same key with the latest value, so slow clients receive the current state instead of every intermediate change.

Why disconnect a slow client instead of buffering?

Answer

Unbounded buffering threatens the server's memory and other clients; disconnecting forces a clean reconnect and state resync.

Open in the app to mark lessons complete, take notes and track your progress.