Skip to content

Reconnect tuning

The SDK reconnects automatically on transient drops. The defaults are sensible for most use cases — tune them when you have specific constraints.

{
initialDelayMs: 1000, // first attempt waits 1 second
maxDelayMs: 30000, // delay caps at 30 seconds
factor: 2, // delay doubles after each failure
jitter: 0.3, // ±30% random jitter on each delay
maxAttempts: Infinity // retry forever
}

This produces an exponential backoff: 1s → 2s → 4s → 8s → 16s → 30s → 30s → … with jitter to avoid thundering herd if many clients reconnect simultaneously.

Network blips, gateway restarts, intermediate proxy resets — anything where reconnecting after a delay is sensible. The reconnect path does not trigger on auth failures (close codes 4001, 4002, 4003); those are fatal and stop the client immediately.

Specifically, the SDK reconnects after:

  • Any close code outside [4001, 4002, 4003].
  • Any low-level WebSocket error (DNS, TCP reset, TLS handshake failure).
  • A clean 1000 close from the server (in case the server is recycling connections).

For batch jobs or scripts where indefinite retry doesn’t make sense, set maxAttempts:

const client = createClient({
url, apiKey,
reconnect: { maxAttempts: 10 }
})
client.on('error', ({ message, fatal }) => {
if (fatal) console.error('giving up after retries:', message)
})

When maxAttempts is reached, the SDK emits error with fatal: true and stops. A new createClient(...) is required to retry.

For a UI where a transient blip should recover quickly:

reconnect: {
initialDelayMs: 250,
maxDelayMs: 5000,
factor: 1.5
}

Trade-off: more reconnect chatter against the gateway during longer outages. Don’t go below ~250ms — at that point you’re hammering rather than reconnecting.

There’s no flag for “don’t reconnect”. If you really want one-shot, set maxAttempts: 0:

reconnect: { maxAttempts: 0 }

The first transient drop will fire error: { fatal: true } and the client will stop.

Subscribe to reconnecting to surface state in your UI:

client.on('reconnecting', ({ attempt, delayMs }) => {
ui.show(`Reconnecting (attempt ${attempt}, in ${Math.round(delayMs / 1000)}s)…`)
})
client.on('connected', () => ui.hide())

delayMs is the actual delay including jitter — so the value you see is what the SDK is really about to wait, not the nominal delay.

If you’d rather poll than subscribe:

client.connectionState // { status, lastError? }
// status: 'disconnected' | 'connecting' | 'connected' | 'reconnecting'

Use the lifecycle events for reactivity, connectionState for the occasional point-in-time read.

If you want to cancel a connection attempt — e.g. the user navigated away — pass an AbortSignal to connect():

const ctrl = new AbortController()
client.connect({ signal: ctrl.signal }).catch(err => {
if (err.name === 'AbortError') return // expected
throw err
})
// later, to cancel:
ctrl.abort()

The promise rejects with AbortError and the client is fully torn down.