fix: use exponential backoff with jitter for WebSocket reconnection

Replace fixed 3s reconnect delay with exponential backoff (1s → 30s cap)
plus 30% jitter to prevent thundering herd. Resets on successful
connection or manual disconnect.
This commit is contained in:
Nicolas Varrot
2026-02-11 22:33:02 +00:00
parent 85c23b4e2d
commit f8be728842

View File

@@ -24,6 +24,7 @@ export class GatewayClient {
private eventHandlers: GatewayEventHandler[] = []; private eventHandlers: GatewayEventHandler[] = [];
private _onStatus: (s: 'disconnected' | 'connecting' | 'connected') => void = () => {}; private _onStatus: (s: 'disconnected' | 'connecting' | 'connected') => void = () => {};
private reconnectTimer: ReturnType<typeof setTimeout> | null = null; private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
private reconnectAttempts = 0;
private connected = false; private connected = false;
private autoReconnect = true; private autoReconnect = true;
@@ -109,6 +110,7 @@ export class GatewayClient {
}).then((res) => { }).then((res) => {
console.log('[GW] connected!', res); console.log('[GW] connected!', res);
this.connected = true; this.connected = true;
this.reconnectAttempts = 0;
this._onStatus('connected'); this._onStatus('connected');
}).catch((err) => { }).catch((err) => {
console.log('[GW] connect failed:', err); console.log('[GW] connect failed:', err);
@@ -119,14 +121,20 @@ export class GatewayClient {
private scheduleReconnect() { private scheduleReconnect() {
if (this.reconnectTimer) return; if (this.reconnectTimer) return;
const base = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
const jitter = Math.random() * base * 0.3;
const delay = base + jitter;
this.reconnectAttempts++;
console.log(`[GW] reconnecting in ${Math.round(delay)}ms (attempt ${this.reconnectAttempts})`);
this.reconnectTimer = setTimeout(() => { this.reconnectTimer = setTimeout(() => {
this.reconnectTimer = null; this.reconnectTimer = null;
this.connect(); this.connect();
}, 3000); }, delay);
} }
disconnect() { disconnect() {
this.autoReconnect = false; this.autoReconnect = false;
this.reconnectAttempts = 0;
if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }
if (this.ws) { this.ws.close(); this.ws = null; } if (this.ws) { this.ws.close(); this.ws = null; }
this.connected = false; this.connected = false;