Area: streaming (api) · ops — reliability gap · found via WaveHouse-Stats dogfooding (reproduced live)
Expected: a long-lived SSE stream survives through a CDN/proxy even with no events flowing.
Actual: the handler writes : connected once (internal/api/stream.go:67) then sends nothing until an event arrives — the select loop (:116-145) has only context-done and incoming-event cases, no heartbeat ticker. On a quiet stream an intermediary (Cloudflare's edge idle-timeout, ~2 min) resets the idle HTTP/2 stream with INTERNAL_ERROR. Browser EventSource auto-reconnects so it's masked there, but curl/server-side consumers drop repeatedly and each reconnect re-runs gap-fill.
Impact (Stats): curl against /v1/stream?table=gh_events dies ~every 2 min while the table is quiet; we wrap it in a reconnect loop.
Scope: periodic SSE comment heartbeat on a ticker, added to the select loop.
Related: SSE per-subscriber channel buffer sizing #152 (same handler).
From WAVEHOUSE-FEEDBACK.md (WaveHouse-Stats dogfooding); validated by code-read against 0f8826c on 2026-06-04.
Area: streaming (api) · ops — reliability gap · found via WaveHouse-Stats dogfooding (reproduced live)
Expected: a long-lived SSE stream survives through a CDN/proxy even with no events flowing.
Actual: the handler writes
: connectedonce (internal/api/stream.go:67) then sends nothing until an event arrives — the select loop (:116-145) has only context-done and incoming-event cases, no heartbeat ticker. On a quiet stream an intermediary (Cloudflare's edge idle-timeout, ~2 min) resets the idle HTTP/2 stream withINTERNAL_ERROR. BrowserEventSourceauto-reconnects so it's masked there, butcurl/server-side consumers drop repeatedly and each reconnect re-runs gap-fill.Impact (Stats):
curlagainst/v1/stream?table=gh_eventsdies ~every 2 min while the table is quiet; we wrap it in a reconnect loop.Scope: periodic SSE comment heartbeat on a ticker, added to the select loop.
Related: SSE per-subscriber channel buffer sizing #152 (same handler).
From
WAVEHOUSE-FEEDBACK.md(WaveHouse-Stats dogfooding); validated by code-read against0f8826con 2026-06-04.