Skip to content

Lifecycle

This document describes the complete lifecycle of a WebSocket connection: from opening the socket, authenticating, joining rooms, receiving updates, keeping alive with heartbeats, disconnecting, and reconnecting with state recovery.

Reference: connection.md · authentication.md · rooms.md · events/auction.md


The lifecycle at a glance

Connection
Authentication
Join Rooms
Receive Updates
Heartbeat
Disconnect
Reconnect

Stage 1 — Connection

  1. The client opens a WebSocket to wss://api.example.com/ws (TLS, RFC 6455).
  2. The client supplies an access token (header or bearer.<token> subprotocol) and the websocket.v1 subprotocol.
  3. The server upgrades the request and verifies the token.

Failure at this stage closes the socket with code 1008 / Authentication failed (see connection.md).

Stage 2 — Authentication

  • The server decodes the access token and builds a SocketUser (userId, role, companyId, permissions).
  • There is no unauthenticated window; the socket is only "open" for processing once the token is valid.

See authentication.md.

Stage 3 — Join rooms

After the handshake the client typically:

  • subscribes to auctions with auction.subscribe (joins auction:<cycleId>),
  • optionally joins company:<id>, user:<id>, notifications, or admins with room.join.

The server authorizes each join; disallowed joins return FORBIDDEN.

Stage 4 — Receive updates

  • auction.subscribe triggers auction.connected, auction.snapshot, and presence.snapshot.
  • Live bids, presence transitions, and state changes arrive as server-pushed events (see events/auction.md).
  • The client applies the snapshot as a base and then the deltas.

Stage 5 — Heartbeat

  • The server sends protocol ping every 20 s; clients auto-answer pong.
  • Missed pong → the server terminates the connection (see connection.md).

Stage 6 — Disconnect

On close/error, the server:

  1. stops the heartbeat,
  2. runs every subscription cleanup (unsubscribe from realtime + presence leave),
  3. leaves all rooms,
  4. removes the connection from the connection manager,
  5. logs the closure.

All server-side state tied to the connection is released automatically.

Stage 7 — Reconnect

The client reconnects with a fresh token and restores state:

  1. Open a new socket.
  2. Re-auction.subscribe with lastSequence to replay missed events.
  3. Re-join rooms.
  4. Apply the new auction.snapshot.

Sequence diagram

sequenceDiagram
    participant C as Client
    participant S as WebSocket Server
    participant R as Redis Pub/Sub

    Note over C,S: CONNECT
    C->>S: WS upgrade + token (websocket.v1, bearer.<token>)
    alt valid token
        S-->>C: 101 Switching Protocols
    else invalid token
        S--xC: close 1008
    end

    Note over C,S: AUTHENTICATED
    C->>S: auction.subscribe { cycleId, lastSequence? }
    S->>S: authorize + join auction:<cycleId>
    S->>R: ensure ws:room:auction:<cycleId>
    S-->>C: auction.connected
    S-->>C: auction.snapshot
    S-->>C: presence.snapshot
    S-->>C: ack

    Note over C,S: UPDATES
    loop live events
        R--)S: ws:room:auction:<cycleId>
        S-->>C: bid.created / auction.started / presence.joined ...
    end

    Note over C,S: HEARTBEAT
    loop every 20s
        S-->>C: ping
        C-->>S: pong
    end

    Note over C,S: DISCONNECT
    alt network failure / close
        C--xS: close
        S->>R: unsubscribe channel when room empty
        S->>S: cleanup rooms + presence + heartbeat
    end

    Note over C,S: RECONNECT
    C->>S: reconnect with fresh token
    C->>S: auction.subscribe { cycleId, lastSequence }
    S-->>C: auction.snapshot (+ replayed events)

State transitions

State Entered when Actions Exit
connecting client opens socket authenticating or closed (handshake fail)
authenticating upgrade request received verify token open or closed (code 1008)
open token valid register connection, start heartbeat closing / closed
subscribed first room/auction join join rooms, subscribe redis, presence join open (on unsubscribe)
closing client/server close run subscription cleanup closed
closed socket closed remove connection, leave rooms, stop heartbeat — (may reconnect)

Resource cleanup checklist (server)

Resource Released on
Heartbeat timer connection close
Room memberships connection close
Redis ws:room:<room> subscription when the room has no members
Auction realtime subscription connection close / auction.unsubscribe
Presence (subscriber) last connection for the enrollment leaves
Connection registry entry connection close

Reconnect checklist (client)

  1. Refresh the access token (REST refresh endpoint).
  2. Open a fresh socket with the new token.
  3. For each active auction: auction.subscribe with lastSequence = last seen serverSequence.
  4. Rejoin company:<id>, user:<id>, notifications, admins as needed.
  5. Discard any in-flight unacknowledged commands with the same idempotencyKey semantics; reuse keys so replays are safe.