add retry loop for local sse reconnection
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user