Managing WebSocket State
1. Tracking Connection State
| State Slice | Storage |
| Connection status | State machine: idle/connecting/open/closing/closed |
| Subscriptions | Set of topics |
| Outbox | Queue of pending sends |
| Inflight RPCs | Map of id → handler |
| Last seq | For resume |
2. Storing Client Data
Example: Attach context
wss.on("connection", (ws, req) => {
ws.ctx = { userId: req.user.id, subs: new Set(), connectedAt: Date.now() };
});
| Storage | Use |
Attached to ws object | Per-connection |
| WeakMap<ws, ctx> | Cleaner ownership |
| Redis | Cross-node shared state |
3. Synchronizing State
| Approach | Detail |
| Snapshot | Send full state on connect |
| Delta + seq | Send changes after snapshot |
| Resync trigger | Client requests on gap detection |
4. Handling State Recovery
Example: Resume protocol
{ "type": "resume", "lastSeq": 4218 }
{ "type": "resumed", "from": 4219, "to": 4235, "events": [ /* ... */ ] }
{ "type": "snapshot", "state": { /* full */ }, "seq": 4500 }
| Server Response | Condition |
| resumed | Buffer still has from lastSeq+1 |
| snapshot | Buffer rolled past; full state needed |
5. Implementing State Snapshots
| Detail | Recommendation |
| Format | Compact (msgpack/protobuf for large) |
| Versioned | Schema version + seq |
| Chunked | Split if > 64KB |
| Trigger | On connect, on resync, periodic |
6. Implementing Delta Updates
Example: JSON Patch (RFC 6902)
{ "type": "patch", "seq": 4501, "ops": [
{ "op": "replace", "path": "/users/u1/status", "value": "online" },
{ "op": "add", "path": "/messages/-", "value": { "id": "m9", "text": "hi" } }
]}
| Format | Lib |
| JSON Patch | fast-json-patch |
| JSON Merge Patch | RFC 7396 |
| Custom ops | Domain-specific |
| Aspect | Detail |
| Concept | Transform concurrent ops against each other |
| Uses | Google Docs-style text editing |
| Server role | Central source-of-truth ordering |
| Library | ShareDB, ot.js |
8. Implementing CRDT
| CRDT Type | Use |
| LWW-Register | Single value, last-write-wins |
| G-Counter | Monotonic counter |
| OR-Set | Add/remove element set |
| Yjs / Automerge | Rich text, JSON CRDT libraries |
Note: CRDTs allow peer-to-peer merges without a central authority. WebSocket transports their update messages but isn't part of the algorithm.
9. Validating State Consistency
| Check | Detail |
| Hash compare | Periodic SHA of state; resync on mismatch |
| Seq monotonicity | Detect gaps / duplicates |
| Schema invariants | Re-validate after each patch |
10. Persisting State
| Storage | Use |
| IndexedDB | Browser-local persistence |
| localStorage | Small KV (<5MB) |
| Redis | Server-side ephemeral |
| Postgres | Durable source-of-truth |