Reconnects and Health
Clients expose health():
connectedlast_message_timestamp_msreconnect_countmessages_receivedmessages_sentlast_errorlast_error_timestamp_msuptime_seconds
Connection retry behavior uses exponential backoff with jitter. Live systems
should monitor last_message_timestamp_ms, reconnect counts, and process-level
logs.
Graceful stream endings
Polymarket, Kalshi, and Opinion recover when the remote websocket iterator
ends normally as well as when it raises a connection error. Each disconnect
sets connected to false, increments reconnect_count once, and waits for
backoff before reconnecting and restoring the saved subscription. Opinion
stops its old heartbeat before waiting and starts a new one after connecting.
A completed socket is never repeatedly read without a retry delay.
close() marks the client stopped before closing the socket and interrupts
pending retry waits. Cancelling the message reader or calling aclose() on
its iterator releases the connection and heartbeat without reconnecting.
Repeated close() calls are safe, including before the first connection.
After closing, call connect() explicitly to start a new session.
Connection manager shutdown
Polymarket, Kalshi, and Opinion connection managers own their background message reader. Always shut a manager down through its public lifecycle:
await manager.start()
try:
...
finally:
await manager.stop()
stop() cancels and awaits the message reader before closing the websocket
client, so it completes even when the stream is idle. Calling stop() before
start() or more than once is safe. Consumers should not inspect or cancel
private task attributes.