WebSocket Connection Lifecycle
This document describes the connection lifecycle events published to
the websocketmanager.lifecycle topic by the WebSocketManager.
Event Types
| Type | When | Data |
|---|---|---|
connection.connected |
Connection established with the upstream WS server | connection_id, url, instance_id, reason (previous status) |
connection.disconnected |
Connection closed (any reason) | connection_id, url, instance_id, reason (previous status) |
connection.reconnecting |
Auto-reconnect attempt in progress | connection_id, url, instance_id, reason (previous status), attempt (reconnect attempt number) |
connection.error |
Receive loop caught an unexpected exception | connection_id, url, instance_id, error_type, error_message |
attempt is currently always 1: the WSM fires exactly one
connection.reconnecting event before entering its retry loop, not
one per attempt, so the field reflects the upcoming first attempt
rather than a live counter.
All events are CloudEvents v1.0 envelopes. Subscribe via
Pubsub.Subscribe(topic: Topics.Lifecycle) on the virtufin-api;
subscribers from outside the WSM process can hardcode
"websocketmanager.lifecycle" (the string source of truth is
websocketmanager/src/Virtufin.WebSocketManager/Configuration/Topics.cs:Lifecycle).
Scenarios
Scenario 1: Server initiates close (e.g. Binance terminates the connection)
The WebSocket server sends a Close frame. The wrapper detects it and:
- If
auto_reconnect = true: firesconnection.reconnecting, then eitherconnection.connected(on successful reconnect) orconnection.disconnected(afterReconnectMaxAttemptsis exhausted). - If
auto_reconnect = false: firesconnection.disconnected.
Consumer guidance: treat connection.reconnecting as a transient
signal. Wait for connection.connected or connection.disconnected
before taking corrective action. The backoff is exponential, capped at
ReconnectBaseDelayMs.
Scenario 2: Network error disconnects the connection
The receive loop catches an exception (WebSocketException,
IOException, etc.). The wrapper fires connection.error FIRST (with
the exception context), then follows the same path as Scenario 1:
connection.reconnecting (or connection.disconnected) → final state.
Consumer guidance: connection.error provides diagnostic context
(exception type, message). It always precedes a state transition, so
subscribe to it for monitoring but always handle the subsequent
connection.reconnecting / connection.disconnected for the actual
recovery action.
Scenario 3: User-initiated disconnect
The user calls Disconnect on the worker. The wrapper fires
connection.disconnected only (no connection.reconnecting).
Scenario 4: Initial connect
The user calls Create then issues a connect command. The wrapper
fires connection.connected once the upstream WebSocket handshake
completes.
Event Ordering Guarantees
connection.erroris always followed by eitherconnection.reconnectingorconnection.disconnected.connection.reconnectingis always followed by eitherconnection.connected(success) orconnection.disconnected(exhausted).- Events for the same
connection_idare delivered in the order they occur in the wrapper.
Best-Effort Delivery
The lifecycle publisher is best-effort. If the virtufin-api is unreachable, the wrapper logs a warning and continues. The connection's state is still updated locally; only the cross-service event is dropped.