Phase 5 · Advanced Node.js & ArchitectureModule 36~68 min read

WebSockets & Real-Time Systems

Build authenticated real-time channels with connection lifecycle, heartbeats, rooms, ordering, backpressure, and horizontal scaling.

What you'll learn

A WebSocket is a long-lived, bidirectional transport, not a complete protocol. Define authentication, message schemas, acknowledgements, ordering, heartbeats, backpressure, reconnects, and horizontal fan-out.

By the end of this lesson, you'll be able to:

  • Authenticate connection and messages
  • Design a versioned message protocol
  • Detect dead peers and slow consumers
  • Scale rooms across replicas

Core mental model

Node.js becomes easier when you separate the JavaScript language from the runtime and the operating-system capabilities it exposes. Use this table as a decision guide.

ConceptWhat it meansDecision rule
HandshakeHTTP upgrade establishing a socketAuthenticate origin and credential before accepting
HeartbeatPing/pong liveness detectionTerminate silent peers and let clients reconnect
BackpressureOutbound data exceeds client capacityBound buffers, drop noncritical events, or disconnect

Professional workflow

Build and verify Node.js programs from the terminal in small, observable steps.

  1. Define the real-time protocol boundary: inputs, outputs, invariants, ownership, and expected failures.
  2. Design the data or message contract before choosing implementation details.
  3. Implement the smallest correct path with dependencies passed explicitly.
  4. Add validation, failure translation, cleanup, and concurrency behavior.
  5. Verify the boundary with realistic data and at least one adversarial case.
  6. Measure or observe the behavior before optimizing or extracting abstractions.

Keep the feedback loop short

Run the smallest useful command after every meaningful change. Read the complete error message before editing again, and keep inputs and outputs visible while you learn.

Guided code lab

Validate every message envelope

Connection identity is trusted server context while each incoming message is parsed, authorized, and acknowledged.

gateway.js
socket.on('message', async (bytes) => {
  const message = messageSchema.parse(JSON.parse(bytes.toString('utf8')));
  if (!can(socket.subject, message.type, message.roomId)) {
    return socket.send(JSON.stringify({ id: message.id, ok: false, code: 'forbidden' }));
  }
  const result = await commands.handle(socket.subject, message);
  socket.send(JSON.stringify({ id: message.id, ok: true, result }));
});

Production practice

Contract

The protocol versions envelope, IDs, event types, payload schemas, authorization, acknowledgement, error codes, and ordering guarantees.

Verification

Test invalid origin/token/message, cross-room access, duplicate IDs, reconnect replay, heartbeat timeout, slow clients, and two-replica fan-out.

Operations

Limit connections and message rates, cap buffered bytes, publish through authenticated channels, and observe active sockets and delivery lag.

Common failure mode

Authorizing only the handshake lets a valid user send messages for rooms or tenants they cannot access.

Independent workshop

Add authenticated live task updates and presence.

Your finished workshop must include:

  • Versioned envelopes
  • Handshake authentication
  • Per-message authorization
  • Heartbeat
  • Reconnect strategy
  • Cross-replica pub/sub

Definition of done

Run the happy path and at least two edge cases, keep responsibilities separated, and add a short README explaining how to run the program.

Recap & quick check

Key takeaways

  • Transport is not protocol
  • Messages need schemas
  • Authorization is continuous
  • Heartbeats detect half-open peers
  • Slow consumers need policy

Quick check

1. When is authorization required?

2. What handles a slow consumer?

3. Why include message IDs?

Next: Queues & Background Jobs