Scale display player by switching from SSE to polling
This commit is contained in:
@@ -38,9 +38,6 @@
|
||||
let idx = 0;
|
||||
let timer = null;
|
||||
|
||||
let es = null;
|
||||
let esRetryMs = 1000;
|
||||
|
||||
async function fetchPlaylist() {
|
||||
const qs = sid ? `?sid=${encodeURIComponent(sid)}` : '';
|
||||
const res = await fetch(`/api/display/${token}/playlist${qs}`, { cache: 'no-store' });
|
||||
@@ -115,37 +112,17 @@
|
||||
// keep retrying; if a slot frees up the display will start automatically.
|
||||
}
|
||||
|
||||
// Open live event stream: when server signals a change, reload playlist immediately.
|
||||
connectEvents();
|
||||
|
||||
// Fallback refresh (in case SSE is blocked by a proxy/network): every 5 minutes.
|
||||
// Poll for updates instead of SSE.
|
||||
// This scales better for 100s of displays because it avoids long-lived HTTP
|
||||
// connections (which otherwise tie up gunicorn sync workers).
|
||||
// Default: check every 20s (can be overridden via ?poll=seconds).
|
||||
const pollParam = parseInt(new URLSearchParams(window.location.search).get('poll') || '', 10);
|
||||
const pollSeconds = Number.isFinite(pollParam) && pollParam > 0 ? pollParam : 20;
|
||||
setInterval(async () => {
|
||||
try {
|
||||
playlist = await fetchPlaylist();
|
||||
if (!stage.firstChild) {
|
||||
idx = 0;
|
||||
next();
|
||||
}
|
||||
} catch(e) {
|
||||
clearStage();
|
||||
setNotice(e && e.message ? e.message : 'Unable to load playlist.');
|
||||
}
|
||||
}, 300000);
|
||||
}
|
||||
|
||||
function connectEvents() {
|
||||
if (isPreview) return; // preview shouldn't consume a slot / keep a long-lived connection
|
||||
|
||||
try { if (es) es.close(); } catch(e) { /* ignore */ }
|
||||
|
||||
const qs = sid ? `?sid=${encodeURIComponent(sid)}` : '';
|
||||
es = new EventSource(`/api/display/${token}/events${qs}`);
|
||||
|
||||
es.addEventListener('changed', async () => {
|
||||
try {
|
||||
const newPlaylist = await fetchPlaylist();
|
||||
|
||||
// If content changed, restart from the beginning.
|
||||
// Restart if something changed.
|
||||
const oldStr = JSON.stringify(playlist);
|
||||
const newStr = JSON.stringify(newPlaylist);
|
||||
playlist = newPlaylist;
|
||||
@@ -154,21 +131,16 @@
|
||||
next();
|
||||
}
|
||||
|
||||
esRetryMs = 1000; // reset backoff on success
|
||||
// If player is blank (e.g. after a temporary error), kick it.
|
||||
if (!stage.firstChild) {
|
||||
idx = 0;
|
||||
next();
|
||||
}
|
||||
} catch(e) {
|
||||
// leave current playback; we'll retry via reconnect handler
|
||||
clearStage();
|
||||
setNotice(e && e.message ? e.message : 'Unable to load playlist.');
|
||||
}
|
||||
});
|
||||
|
||||
es.onerror = () => {
|
||||
try { es.close(); } catch(e) { /* ignore */ }
|
||||
es = null;
|
||||
|
||||
// Exponential backoff up to 30s
|
||||
const wait = esRetryMs;
|
||||
esRetryMs = Math.min(30000, Math.floor(esRetryMs * 1.7));
|
||||
setTimeout(connectEvents, wait);
|
||||
};
|
||||
}, pollSeconds * 1000);
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
Reference in New Issue
Block a user