fix: stop aggressive API polling and SSE reconnect when auth lost
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s

When unauthenticated (TOTP gate active), the dashboard was polling
/api/v1/services/status every few seconds and reconnecting SSE every
2-8s indefinitely. Now: 401/403 sets _dcAuthLost flag to skip the
polling interval, and SSE stops after 5 consecutive failures.
This commit is contained in:
Hermes
2026-08-13 14:40:56 -07:00
parent 2ada4694a2
commit 89968f5485
5 changed files with 56 additions and 35 deletions
+6
View File
@@ -401,9 +401,15 @@
refreshInFlight = (async () => {
try {
const response = await fetch('/api/v1/services/status', { cache: 'no-store' });
if (response.status === 401 || response.status === 403) {
// Auth lost — stop the polling loop from hammering every few seconds
window._dcAuthLost = true;
throw new Error(`Authentication required (${response.status})`);
}
if (!response.ok) {
throw new Error(`Status refresh failed (${response.status})`);
}
window._dcAuthLost = false; // auth working again
const data = await response.json();
applyBatchResults(data.statuses || {});
updateStamp('last check', data.checkedAt || new Date());
+6 -1
View File
@@ -63,7 +63,12 @@
window.buildGrid();
animateTopCards();
window.refreshAll();
setInterval(window.refreshAll, DC.POLL.DASHBOARD);
setInterval(() => {
// Stop polling if the session has been invalidated (e.g. TOTP gate
// now active, or user logged out). Avoids relentless 401/403 noise.
if (window._dcAuthLost) return;
window.refreshAll();
}, DC.POLL.DASHBOARD);
if (typeof window.refreshCredsButtons === 'function') window.refreshCredsButtons();
if (typeof window.refreshMonitoringWidgets === 'function') window.refreshMonitoringWidgets();
// Update auth card (may have already been updated by the auto-load IIFE but ensure it's correct)
+10
View File
@@ -11,6 +11,7 @@
es.addEventListener('connected', () => {
reconnectDelay = 1000; // reset backoff
_sseFailCount = 0; // reset failure counter
debug('[SSE] Connected to event stream');
});
@@ -101,12 +102,21 @@
// Reconnect on error
es.onerror = () => {
es.close();
// Stop reconnecting entirely after multiple consecutive failures
// (likely auth-gate / session expired — no point hammering forever)
_sseFailCount = (_sseFailCount || 0) + 1;
if (_sseFailCount > 5) {
console.warn('[SSE] Max reconnect attempts reached — stopping (auth gate active or server unreachable)');
return;
}
console.warn(`[SSE] Disconnected, reconnecting in ${reconnectDelay / 1000}s...`);
setTimeout(connect, reconnectDelay);
reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT);
};
}
let _sseFailCount = 0;
// Start on page load
connect();