fix: resolve ERR_INSUFFICIENT_RESOURCES connection exhaustion

- Add concurrency limiter (max 4 GET requests) to API layer, leaving
  slots for SSE and health checks. Write ops bypass the limiter.
- Add AbortController to ContainerStats, project detail page, and
  dashboard to cancel in-flight requests on navigation/unmount.
- Move global SSE connection from layout to events page (only consumer).
- Add 30s heartbeat to SSE endpoint to detect zombie connections.
- Serialize dashboard project fetches to avoid parallel burst.
- Rebuild frontend in dev-server.sh so go:embed stays in sync.
This commit is contained in:
2026-04-13 00:12:14 +03:00
parent 791cd4d6af
commit 96fd910603
7 changed files with 233 additions and 87 deletions
+9 -8
View File
@@ -8,8 +8,7 @@
import { fetchEventLog, fetchEventLogStats, clearAllEvents, deleteEvent } from '$lib/api';
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
import { toasts } from '$lib/stores/toast';
import { subscribeEventLog } from '$lib/stores/event-log-bus';
import type { EventLogSSEPayload } from '$lib/sse';
import { connectGlobalEvents, type SSEConnection, type EventLogSSEPayload } from '$lib/sse';
import type { EventLogEntry, EventLogStats } from '$lib/types';
import EventLogEntryComponent from '$lib/components/EventLogEntry.svelte';
import EventLogFilter from '$lib/components/EventLogFilter.svelte';
@@ -36,7 +35,7 @@
const PAGE_SIZE = 50;
let offset = $state(0);
let unsubscribeEventLog: (() => void) | null = null;
let sseConnection: SSEConnection | null = null;
let listEl: HTMLDivElement | undefined = $state();
let showClearConfirm = $state(false);
@@ -199,15 +198,17 @@
loadEvents();
loadStats();
// Subscribe to event_log events from the global SSE connection (no duplicate connection).
unsubscribeEventLog = subscribeEventLog((payload: EventLogSSEPayload) => {
handleSSEEvent(payload);
// Open SSE connection only while this page is mounted.
sseConnection = connectGlobalEvents({
onEventLog(payload) {
handleSSEEvent(payload);
}
});
});
onDestroy(() => {
unsubscribeEventLog?.();
unsubscribeEventLog = null;
sseConnection?.close();
sseConnection = null;
});
</script>