diff --git a/electron/gateway/manager.ts b/electron/gateway/manager.ts index df6e40c..3a3b581 100644 --- a/electron/gateway/manager.ts +++ b/electron/gateway/manager.ts @@ -155,7 +155,12 @@ export class GatewayManager extends EventEmitter { private static readonly HEARTBEAT_TIMEOUT_MS_WIN = 25_000; private static readonly HEARTBEAT_MAX_MISSES_WIN = 5; public static readonly RESTART_COOLDOWN_MS = 5_000; - private static readonly GATEWAY_READY_FALLBACK_MS = 30_000; + // Fallback for the server-side gateway.ready event: if the event doesn't + // arrive within this window after the WS handshake completes, we assume the + // gateway is effectively ready so downstream consumers don't block forever. + // Kept short (5s) because handshake completion already implies a working + // RPC channel — this is only a safety net, not the primary signal. + private static readonly GATEWAY_READY_FALLBACK_MS = 5_000; private lastRestartAt = 0; /** Set by scheduleReconnect() before calling start() to signal auto-reconnect. */ private isAutoReconnectStart = false; diff --git a/tests/unit/gateway-ready-fallback.test.ts b/tests/unit/gateway-ready-fallback.test.ts index 8cd9596..62cfd1d 100644 --- a/tests/unit/gateway-ready-fallback.test.ts +++ b/tests/unit/gateway-ready-fallback.test.ts @@ -90,10 +90,10 @@ describe('GatewayManager gatewayReady fallback', () => { (manager as unknown as { scheduleGatewayReadyFallback: () => void }).scheduleGatewayReadyFallback(); // Before timeout, no gatewayReady update - vi.advanceTimersByTime(29_000); + vi.advanceTimersByTime(4_000); expect(statusUpdates.find((u) => u.gatewayReady === true)).toBeUndefined(); - // After 30s fallback timeout + // After fallback timeout (5s) vi.advanceTimersByTime(2_000); const readyUpdate = statusUpdates.find((u) => u.gatewayReady === true); expect(readyUpdate).toBeDefined(); @@ -115,13 +115,13 @@ describe('GatewayManager gatewayReady fallback', () => { // Schedule fallback (manager as unknown as { scheduleGatewayReadyFallback: () => void }).scheduleGatewayReadyFallback(); - // gateway:ready event arrives at 5s - vi.advanceTimersByTime(5_000); + // gateway:ready event arrives before fallback (at 1s, well under 5s) + vi.advanceTimersByTime(1_000); manager.emit('gateway:ready', {}); expect(statusUpdates.filter((u) => u.gatewayReady === true)).toHaveLength(1); - // After 30s, no duplicate gatewayReady=true - vi.advanceTimersByTime(30_000); + // Well past the fallback window, no duplicate gatewayReady=true + vi.advanceTimersByTime(10_000); expect(statusUpdates.filter((u) => u.gatewayReady === true)).toHaveLength(1); }); });