Dashboard: make LIVE not depend on the SSE stream
LIVE rendered ONLY from the EventSource snapshot handler — and that handler
swallowed render/parse errors (catch {}). If EventSource didn't establish in the
user's browser (proxy, extension, connection cap), LIVE stayed blank while the
date selector — a plain fetch — worked fine. Exactly the reported symptom.
- startStream() now does an immediate pollOnce() (the same fetch path the date
selector uses) so LIVE shows data even if SSE never connects; SSE then layers
on for low-latency pushes, with onerror -> interval polling as before.
- Surface render errors (console + conn status) instead of hiding them.
- Serve the dashboard HTML with no-store/no-cache so pushed fixes actually reach
the browser (a stale cached shell was part of why "I see nothing" persisted).
Verified headless: with EventSource forcibly disabled, LIVE still populates
(10 armed rows, pnl, risk) via the polling fallback — stamp shows "polling ·".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
c14a89585a
commit
506ff253ec
2 files changed
+12
-2
No files matched your search
@@ -257,6 +257,11 @@ class DashboardHandler(BaseHTTPRequestHandler):
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/html; charset=utf-8")
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
# never cache the dashboard shell — a stale cached page was serving old
|
||||
# JS/CSS, so pushed fixes (and live-vs-cached behaviour) didn't reach the
|
||||
# browser. The page is tiny and the data is fetched separately anyway.
|
||||
self.send_header("Cache-Control", "no-store, no-cache, must-revalidate")
|
||||
self.send_header("Pragma", "no-cache")
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
|
||||
@@ -793,13 +793,18 @@ function setConn(ok, msg) {
|
||||
$("stamp").textContent = msg;
|
||||
}
|
||||
function startStream() {
|
||||
// Render immediately from a plain fetch (the same reliable path the date
|
||||
// selector uses) so LIVE shows data even if EventSource never connects in
|
||||
// this browser/proxy. SSE then layers on for low-latency pushes.
|
||||
pollOnce();
|
||||
if (typeof EventSource === "undefined") { startPolling(); return; }
|
||||
try {
|
||||
es = new EventSource("/api/stream");
|
||||
es.addEventListener("snapshot", (ev) => {
|
||||
try { render(JSON.parse(ev.data)); setConn(true, "live · " + new Date().toLocaleTimeString()); }
|
||||
catch (e) {}
|
||||
catch (e) { console.error("render failed:", e); setConn(false, "render error (see console)"); }
|
||||
});
|
||||
es.onerror = () => { setConn(false, "stream lost — polling"); es.close(); es = null; startPolling(); };
|
||||
es.onerror = () => { setConn(false, "stream lost — polling"); if (es) es.close(); es = null; startPolling(); };
|
||||
} catch (e) { startPolling(); }
|
||||
}
|
||||
async function pollOnce() {
|
||||
|
||||
Reference in new issue
Block a user