Skip to content

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: fires connection.reconnecting, then either connection.connected (on successful reconnect) or connection.disconnected (after ReconnectMaxAttempts is exhausted).
  • If auto_reconnect = false: fires connection.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.error is always followed by either connection.reconnecting or connection.disconnected.
  • connection.reconnecting is always followed by either connection.connected (success) or connection.disconnected (exhausted).
  • Events for the same connection_id are 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.