Problem
When the Rust backend restarts during a deploy, the SSE EventSource connection receives an HTTP 500 and enters the CLOSED state (readyState = 2). The current implementation in src/lib/hooks/use-sse-connection.ts closes the connection permanently and sets an error state — it never retries.
This means users lose real-time updates (action/agreement/goal change notifications) until they manually refresh the page.
Current behavior
In use-sse-connection.ts:
readyState === EventSource.CONNECTING → browser auto-retries (network errors)
readyState === EventSource.CLOSED → connection is closed permanently, no retry
Proposed solution
Add manual reconnection with exponential backoff when the EventSource enters the CLOSED state due to a server error (500/502/503). Key considerations:
- Exponential backoff with jitter — base delay 1s, max 30s, add random jitter to prevent thundering herd when many clients reconnect after a server restart
- Max retry limit — stop after ~8 attempts to avoid infinite retry loops
- Reset on success — clear retry counter when connection is re-established
- Don't retry on auth errors — 401/403 should still close permanently (the current
force_logout SSE event handles this)
- Consider migrating from native EventSource to
fetch + ReadableStream — native EventSource cannot send custom headers (API version header), and the retry behavior is browser-dependent
Files to modify
src/lib/hooks/use-sse-connection.ts — add retry logic
src/lib/stores/sse-connection-store.ts — potentially track retry count/state
Research notes
- Native EventSource behavior on HTTP 500 varies by browser (spec says CLOSED, most browsers agree)
@microsoft/fetch-event-source is the most popular library for controlled SSE (~1.5M weekly downloads) but hasn't been updated since 2023
- A manual
fetch + ReadableStream implementation avoids the dependency and gives full control over headers and retry
Problem
When the Rust backend restarts during a deploy, the SSE EventSource connection receives an HTTP 500 and enters the
CLOSEDstate (readyState = 2). The current implementation insrc/lib/hooks/use-sse-connection.tscloses the connection permanently and sets an error state — it never retries.This means users lose real-time updates (action/agreement/goal change notifications) until they manually refresh the page.
Current behavior
In
use-sse-connection.ts:readyState === EventSource.CONNECTING→ browser auto-retries (network errors)readyState === EventSource.CLOSED→ connection is closed permanently, no retryProposed solution
Add manual reconnection with exponential backoff when the EventSource enters the CLOSED state due to a server error (500/502/503). Key considerations:
force_logoutSSE event handles this)fetch+ReadableStream— native EventSource cannot send custom headers (API version header), and the retry behavior is browser-dependentFiles to modify
src/lib/hooks/use-sse-connection.ts— add retry logicsrc/lib/stores/sse-connection-store.ts— potentially track retry count/stateResearch notes
@microsoft/fetch-event-sourceis the most popular library for controlled SSE (~1.5M weekly downloads) but hasn't been updated since 2023fetch+ReadableStreamimplementation avoids the dependency and gives full control over headers and retry