mirror of
https://github.com/etiennecollin/unifi-voucher-manager.git
synced 2025-10-23 00:02:10 +00:00
fix: handle SSE reconnections
This commit is contained in:
@@ -1,15 +1,35 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect, useRef, useCallback } from "react";
|
||||
|
||||
function getBackoffDelay(attempt: number, base = 1000, max = 30000) {
|
||||
const jitter = Math.random() * 0.3 + 0.85; // 85–115% random factor
|
||||
return Math.min(base * Math.pow(2, attempt), max) * jitter;
|
||||
}
|
||||
|
||||
export function useServerEvents() {
|
||||
const eventSourceRef = useRef<EventSource | null>(null);
|
||||
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const reconnectAttempts = useRef(0);
|
||||
const maxReconnectAttempts = 5;
|
||||
|
||||
const connect = useCallback(() => {
|
||||
// Avoid reconnecting if already connecting/open
|
||||
if (
|
||||
eventSourceRef.current &&
|
||||
(eventSourceRef.current.readyState === EventSource.OPEN ||
|
||||
eventSourceRef.current.readyState === EventSource.CONNECTING)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close existing connection if any
|
||||
eventSourceRef.current?.close();
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Setting up SSE connection...");
|
||||
|
||||
eventSourceRef.current = new EventSource("/api/events");
|
||||
|
||||
eventSourceRef.current.onopen = () => {
|
||||
console.log("SSE connection opened");
|
||||
reconnectAttempts.current = 0;
|
||||
};
|
||||
|
||||
eventSourceRef.current.onmessage = (event) => {
|
||||
@@ -23,6 +43,7 @@ export function useServerEvents() {
|
||||
window.dispatchEvent(new CustomEvent("vouchersUpdated"));
|
||||
break;
|
||||
default:
|
||||
console.warn("Unknown SSE event type:", data.type);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -30,14 +51,39 @@ export function useServerEvents() {
|
||||
}
|
||||
};
|
||||
|
||||
eventSourceRef.current.onerror = (error) => {
|
||||
console.error("SSE connection error:", error);
|
||||
};
|
||||
eventSourceRef.current.onerror = (_error) => {
|
||||
console.log("SSE connection error, attempting to reconnect...");
|
||||
|
||||
return () => {
|
||||
// Close the current connection
|
||||
eventSourceRef.current?.close();
|
||||
|
||||
// Only attempt to reconnect if we haven't exceeded max attempts
|
||||
if (reconnectAttempts.current < maxReconnectAttempts) {
|
||||
reconnectAttempts.current++;
|
||||
const delay = getBackoffDelay(reconnectAttempts.current);
|
||||
|
||||
console.log(
|
||||
`Reconnecting in ${Math.round(delay)}ms (attempt ${reconnectAttempts.current}/${maxReconnectAttempts})`,
|
||||
);
|
||||
|
||||
reconnectTimeoutRef.current = setTimeout(connect, delay);
|
||||
} else {
|
||||
console.error("Max reconnection attempts reached, giving up");
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
connect();
|
||||
|
||||
return () => {
|
||||
// Clear any pending reconnection attempts
|
||||
reconnectTimeoutRef.current && clearTimeout(reconnectTimeoutRef.current);
|
||||
|
||||
// Close the connection
|
||||
eventSourceRef.current?.close();
|
||||
};
|
||||
}, [connect]);
|
||||
|
||||
return eventSourceRef.current;
|
||||
}
|
||||
|
Reference in New Issue
Block a user