fix(bridge): resolve websocket zombie connection and bounding memory leaks

This commit is contained in:
Variet Worker
2026-03-23 21:11:52 +09:00
parent e21f71baf8
commit ecebec3906
10 changed files with 110 additions and 25 deletions

View File

@@ -122,6 +122,7 @@ export class WSBridgeClient {
private reconnectDelay = INITIAL_RECONNECT_DELAY;
private reconnectTimer: NodeJS.Timeout | null = null;
private heartbeatTimer: NodeJS.Timeout | null = null;
private pongTimeoutTimer: NodeJS.Timeout | null = null;
private authTimer: NodeJS.Timeout | null = null;
// Message queue (survives reconnection)
@@ -245,6 +246,10 @@ export class WSBridgeClient {
ws.on('pong', () => {
// Server responded to our ping — connection is alive
if (this.pongTimeoutTimer) {
clearTimeout(this.pongTimeoutTimer);
this.pongTimeoutTimer = null;
}
});
} else {
// ─── Browser-style WebSocket API (.onopen / .onmessage) ───
@@ -469,6 +474,16 @@ export class WSBridgeClient {
// Node.js ws has .ping(), browser WebSocket doesn't
if (typeof this.ws.ping === 'function') {
this.ws.ping();
// Set timeout waiting for pong
if (this.pongTimeoutTimer) clearTimeout(this.pongTimeoutTimer);
this.pongTimeoutTimer = setTimeout(() => {
this.logFn('[WS] Heartbeat timeout — no pong received, terminating connection');
if (this.ws) {
try { this.ws.terminate(); } catch { try { this.ws.close(); } catch { } }
}
this._onDisconnect();
}, 10000); // 10s timeout
} else {
// Fallback: send heartbeat as JSON message
this.ws.send(JSON.stringify({ type: 'heartbeat' }));
@@ -485,6 +500,10 @@ export class WSBridgeClient {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
if (this.pongTimeoutTimer) {
clearTimeout(this.pongTimeoutTimer);
this.pongTimeoutTimer = null;
}
}
// ─── Reconnection ───
@@ -540,6 +559,11 @@ export class WSBridgeClient {
this.reconnectTimer = null;
}
if (this.pongTimeoutTimer) {
clearTimeout(this.pongTimeoutTimer);
this.pongTimeoutTimer = null;
}
if (this.ws) {
try {
this.ws.close();