Skip to content

feat: client-side SSE reconnect manager with visible banner#122

Merged
joaomdsg merged 1 commit into
mainfrom
feat/sse-reconnect
Jun 10, 2026
Merged

feat: client-side SSE reconnect manager with visible banner#122
joaomdsg merged 1 commit into
mainfrom
feat/sse-reconnect

Conversation

@joaomdsg

Copy link
Copy Markdown
Member

Critic panel finding #2 (blocker). Dropping the SSE stream left the tab silently frozen. The existing server-side re-bootstrap only runs once a reconnect reaches the server — but on a graceful clean-close deploy (or a persistent 403/session-mismatch) Datastar exhausts its retries first, so the tab never recovers and the user sees nothing.

Change

Inject a small reconnect manager into every page (a Datastar data-init expression, same mechanism as the existing beforeunload hook — no nonce/CSP change). It watches the datastar-fetch lifecycle:

  • retrying → show a visible "Reconnecting…" banner (the freeze is no longer silent)
  • started/finished → clear the banner
  • retries-failed → reload to re-bootstrap a fresh stream + session, jittered (500–2000ms, avoids a fleet stampeding the new pod) and bounded to 3 attempts via a sessionStorage counter so a down server can't pin a reload loop; after that it shows "Please refresh".

Default on; WithoutSSEReconnect() opts out. Covers both the clean-close deploy freeze and the session-403 case (both end in retries-failed).

Why reload rather than re-arm the SSE from JS

Re-issuing Datastar's fetch-based SSE from a raw listener is fragile; a reload re-bootstraps the stream and the session deterministically — the robust path the design converged on.

Tests

  • server-side: the reconnect data-init is present with the datastar-fetch/retries-failed/reload branches; WithoutSSEReconnect() removes it.
  • browser (chromedp, -tags browser, runs locally w/ Chromium — out of CI): verifies the injected IIFE actually evaluates in Datastar (window.__viaRC), the banner appears on retrying, and retries-failed arms the bounded reload. Verified green locally (stable across runs).
  • docs/production.md recovery section documents the new behavior + opt-out.

Default ci-check.sh green (browser test excluded by build tag).

Dropping the SSE stream left the tab silently frozen: the server-side
re-bootstrap can only run once a reconnect reaches the server, but on a
graceful clean-close deploy (or a persistent 403/session mismatch) Datastar
exhausts its retries first and the tab never recovers — with zero user-visible
feedback.

Inject a small reconnect manager into every page (a Datastar data-init
expression). It watches the datastar-fetch lifecycle: shows a "Reconnecting…"
banner while the stream is retrying, and on retries-failed reloads the page —
jittered to avoid a fleet stampeding the new pod, and bounded to 3 attempts via
a sessionStorage counter so a down server can't pin a reload loop — to
re-bootstrap a fresh stream and session. WithoutSSEReconnect() opts out.

Server-side tests assert the manager is present (and the opt-out removes it); a
browser-tagged chromedp test verifies it actually runs in Datastar (the IIFE
evaluates, window.__viaRC is set), the banner appears on `retrying`, and
`retries-failed` arms the bounded reload — verified locally against Chromium.
@joaomdsg
joaomdsg merged commit 6e7f4ba into main Jun 10, 2026
6 checks passed
@joaomdsg
joaomdsg deleted the feat/sse-reconnect branch June 10, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant