Keepalive
The client runs an application-level ping/pong on the open socket. If pongs stop coming back it treats the connection as dead and tears it down, which kicks off a reconnect. A single dropped pong is tolerated, so a brief network blip doesn’t cause a needless reconnect. This is layered on top of the server’s own connection-level keepalive. See Connection lifecycle.Reconnect with resubscribe
When the socket closes unexpectedly, the client reconnects with exponential backoff and jitter, reporting a reconnect before each attempt:subscriptionIds are scoped to a single connection and don’t
survive a reconnect, so the client replays your active subscriptions (the
(market, channel) pairs you asked for) on every new connection. You’ll receive
a fresh SUBSCRIBED ack and a new SNAPSHOT for each. Because resubscribe is
automatic, subscriptions you create before the socket is even open are honored too
(they’re sent once the connection is ready).
The backoff budget resets only once a connection is confirmed by a WELCOME
frame, so a transient drop after a healthy session gets the full retry budget,
while an endpoint that never establishes a session is bounded (see below).
Subscriptions the server permanently retires are not replayed: a STATUS
frame with state: "CLOSED" or "UNSUPPORTED", or an ERROR frame rejecting a
market at subscription time, prunes that entry so it isn’t retried on reconnect.
GOODBYE and terminal disconnects
Before closing a connection the server sends a GOODBYE
frame with a reason. The client treats these two ways:
- Recoverable:
SHUTDOWN,TTL,IDLE_TIMEOUT, andNO_ACTIVE_SUBS(when you still have subscriptions to replay). The client reconnects normally. - Terminal:
AUTH_REVOKEDandKICKED(andNO_ACTIVE_SUBSwhen there’s nothing left to resubscribe). Reconnecting with the same key would be futile, so the client stops.
goodbye: followed by the reason exactly as the
server sent it, for example goodbye:AUTH_REVOKED. Compare against that casing.
When the client stops for good it reports a termination: a terminated event in
TypeScript, the on_terminated callback in Python. This also happens if
reconnecting repeatedly fails without ever establishing a session (a revoked key
or an unreachable endpoint), instead of looping forever.
Termination is final: that client will not reconnect. A fresh client starts with
none of your handlers or subscriptions, so wrap setup in a function that creates
the client, registers handlers, and subscribes, then call it both initially and
on resume.
In Python the iteration also ends, and a terminal failure is raised out of the
async for, so the restart loop is an ordinary while rather than a callback
that re-enters itself.