add retry loop for local sse reconnection

This commit is contained in:
Shantur Rathore
2025-11-16 10:56:09 +00:00
parent 12044988d6
commit 6658c0b15a

View File

@@ -16,8 +16,11 @@ import type {
interface SSEConnection { interface SSEConnection {
instanceId: string instanceId: string
port: number
eventSource: EventSource eventSource: EventSource
status: "connecting" | "connected" | "disconnected" | "error" status: "connecting" | "connected" | "disconnected" | "error"
reconnectAttempts: number
reconnectTimer?: ReturnType<typeof setTimeout>
} }
interface TuiToastEvent { interface TuiToastEvent {
@@ -50,10 +53,13 @@ const [connectionStatus, setConnectionStatus] = createSignal<
class SSEManager { class SSEManager {
private connections = new Map<string, SSEConnection>() private connections = new Map<string, SSEConnection>()
private static readonly MAX_RECONNECT_ATTEMPTS = 3
connect(instanceId: string, port: number): void { connect(instanceId: string, port: number, reconnectAttempts = 0): void {
if (this.connections.has(instanceId)) { const existing = this.connections.get(instanceId)
this.disconnect(instanceId) if (existing) {
this.clearReconnectTimer(existing)
existing.eventSource.close()
} }
const url = `http://localhost:${port}/event` const url = `http://localhost:${port}/event`
@@ -61,8 +67,10 @@ class SSEManager {
const connection: SSEConnection = { const connection: SSEConnection = {
instanceId, instanceId,
port,
eventSource, eventSource,
status: "connecting", status: "connecting",
reconnectAttempts,
} }
this.connections.set(instanceId, connection) this.connections.set(instanceId, connection)
@@ -70,6 +78,7 @@ class SSEManager {
eventSource.onopen = () => { eventSource.onopen = () => {
connection.status = "connected" connection.status = "connected"
connection.reconnectAttempts = 0
this.updateConnectionStatus(instanceId, "connected") this.updateConnectionStatus(instanceId, "connected")
console.log(`[SSE] Connected to instance ${instanceId}`) console.log(`[SSE] Connected to instance ${instanceId}`)
} }
@@ -87,13 +96,14 @@ class SSEManager {
connection.status = "error" connection.status = "error"
this.updateConnectionStatus(instanceId, "error") this.updateConnectionStatus(instanceId, "error")
console.error(`[SSE] Connection error for instance ${instanceId}`) console.error(`[SSE] Connection error for instance ${instanceId}`)
this.handleConnectionLost(instanceId, "Connection to instance lost") this.handleConnectionError(instanceId, "Connection to instance lost")
} }
} }
disconnect(instanceId: string): void { disconnect(instanceId: string): void {
const connection = this.connections.get(instanceId) const connection = this.connections.get(instanceId)
if (connection) { if (connection) {
this.clearReconnectTimer(connection)
connection.eventSource.close() connection.eventSource.close()
this.connections.delete(instanceId) this.connections.delete(instanceId)
this.updateConnectionStatus(instanceId, "disconnected") this.updateConnectionStatus(instanceId, "disconnected")
@@ -143,10 +153,37 @@ class SSEManager {
} }
} }
private handleConnectionError(instanceId: string, reason: string): void {
const connection = this.connections.get(instanceId)
if (!connection) return
connection.eventSource.close()
if (connection.reconnectAttempts >= SSEManager.MAX_RECONNECT_ATTEMPTS) {
this.handleConnectionLost(instanceId, reason)
return
}
const nextAttempt = connection.reconnectAttempts + 1
const delay = Math.min(nextAttempt * 1000, 5000)
connection.reconnectAttempts = nextAttempt
connection.status = "connecting"
this.updateConnectionStatus(instanceId, "connecting")
console.warn(`[SSE] Attempting reconnect ${nextAttempt} for instance ${instanceId}`)
connection.reconnectTimer = setTimeout(() => {
connection.reconnectTimer = undefined
this.connect(instanceId, connection.port, nextAttempt)
}, delay)
}
private handleConnectionLost(instanceId: string, reason: string): void { private handleConnectionLost(instanceId: string, reason: string): void {
const connection = this.connections.get(instanceId) const connection = this.connections.get(instanceId)
if (!connection) return if (!connection) return
this.clearReconnectTimer(connection)
connection.eventSource.close() connection.eventSource.close()
this.connections.delete(instanceId) this.connections.delete(instanceId)
connection.status = "disconnected" connection.status = "disconnected"
@@ -154,6 +191,13 @@ class SSEManager {
this.onConnectionLost?.(instanceId, reason) this.onConnectionLost?.(instanceId, reason)
} }
private clearReconnectTimer(connection: SSEConnection): void {
if (connection.reconnectTimer) {
clearTimeout(connection.reconnectTimer)
connection.reconnectTimer = undefined
}
}
private updateConnectionStatus(instanceId: string, status: SSEConnection["status"]): void { private updateConnectionStatus(instanceId: string, status: SSEConnection["status"]): void {
setConnectionStatus((prev) => { setConnectionStatus((prev) => {
const next = new Map(prev) const next = new Map(prev)