Skip to main content

Module connector

Module connector 

Source
Expand description

Long-lived WebSocket connector + REST-side handle.

The connector is an actor that owns a single bezant::WsClient and drives it forever:

  1. Connect (with exponential-backoff retry).
  2. Subscribe to orders + pnl (always, on every connect).
  3. Loop: dispatch frames into per-topic rings, accept subscribe/unsubscribe commands for market data, watch a heartbeat timeout to detect a stalled socket.
  4. On any disconnect: bump reset_epoch, push a synthetic gap event into every active ring, sleep with backoff, GOTO 1.

Two things CPAPI does that the loop above did not survive, and now does:

  • It REFUSES a subscribe. sor+{} is answered with {"error":"unable to subscribe","code":500,"topic":"sor"} on most reconnects (17 of 20 attempts over Aug–Sep 2026 on one Gateway). That frame used to be filed as an order event and the subscribe was never retried, so the socket stayed up for days with pnl flowing and orders dead. A refusal is now a control frame: it marks the topic SubscriptionState::Refused and schedules a resubscribe with backoff, primed by GET /iserver/accounts (the call CPAPI documents as the precondition for order queries).
  • It re-logs in underneath the socket. The Gateway’s nightly re-auth, or an assisted re-login, mints a new session; a socket bound to the old one keeps heartbeating — so the heartbeat timeout never fires — while every subscription on it is dead. The connector now compares the socket’s session id against /tickle periodically and reconnects when it changes.

EventsHandle is what axum handlers get. Cloneable, cheap, exposes reads against the rings and a command channel into the actor task.

Structs§

ConnectorCfg
Configurable knobs for the connector.
EventsHandle
Cloneable handle the axum handlers use. Reads come straight off the shared ring map; writes go through the command channel.

Functions§

spawn_connector
Spawn the connector task and return a EventsHandle for the axum side. The task owns the bezant::Client reference (cheap, it’s already Arc-wrapped internally) and runs until the binary exits.