Skip to content

ADR-0001. Horizontally-scaled WebSocket via a single Redis pub/sub bus

FieldValue
StatusAccepted
Date2026-03-28
Deciderssignal-team
Supersedes

Context

  • Real-time updates (orders, payments) must reach POS/Admin clients regardless of which Signal instance holds the socket.
  • WebSocket connections are sticky to one process; in-memory client state cannot be shared across replicas.
  • Other services (Sale, Payment) must be able to push to clients without hosting their own WebSocket server.
  • We want a single real-time edge, not a WebSocket server embedded in every service.

Decision

We will run Signal as the only WebSocket server and route all cross-instance / cross-service delivery through a single Redis pub/sub bus.

  • Signal hosts WebSocketServerHelper (subscribe + publish); producers hold a lightweight WebSocketEmitter (publish only).
  • sendToClient delivers locally if the client is on this instance, otherwise re-publishes to Redis for the owning instance.
  • broadcast / sendToRoom always publish to Redis so every instance delivers to its local matching clients.
  • Redis runs in single or cluster mode (APP_ENV_WEBSOCKET_REDIS_*); all participants must share the same instance.

Consequences

ProsCons
Stateless replicas — scale horizontally behind TraefikRedis becomes a hard dependency / single point of failure for fan-out
Producers stay thin (emitter only, no WS server)Cross-instance delivery is best-effort (dropped if no instance subscribed)
One real-time edge to secure and operateAll publishers must be configured against the identical Redis

Alternatives Considered

OptionProsConsWhy rejected
WS server embedded in each serviceNo shared busN servers to secure; clients juggle N socketsOperationally heavy, duplicates auth/encryption
Sticky sessions, no busSimpleBreaks broadcast + cross-instance deliveryDoesn't meet "reach any client" requirement
Kafka as the delivery busAlready presentHigher latency, not built for ephemeral pub/sub fan-outRedis pub/sub fits live delivery better

References

  • signal/src/components/websocket.component.ts (NxWebSocketComponent, bindEmitter)
  • signal/src/services/signal-event.service.ts (sendToClient local/remote routing)
  • Operations — multi-instance fan-out

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.