diff --git a/examples/monitor-web/monitor_web.html b/examples/monitor-web/monitor_web.html index 832f24d..73d2b53 100644 --- a/examples/monitor-web/monitor_web.html +++ b/examples/monitor-web/monitor_web.html @@ -304,6 +304,7 @@ (() => { const KEY_PREFIX = "monitor/"; const POLL_MS = 1000; + const HISTORY_BACKFILL_GAP_SECONDS = Math.max(5, 3 * POLL_MS / 1000); const MAX_HISTORY_SAMPLES = 3600; const HISTORY_RANGES = { "1m": 60, @@ -341,6 +342,7 @@ let currentHostname = location.hostname || "unknown"; let historyAbortController = null; let historyRequestId = 0; + let historyRefreshPromise = null; const chartRelayoutHandlersAttached = new Set(); const hiddenChartTraces = new Map(); @@ -439,6 +441,14 @@ ); }; + const hasHistoryBackfillGap = (epoch) => { + const last = chartSamples[chartSamples.length - 1]; + return ( + last !== undefined && + epoch > last.epoch + HISTORY_BACKFILL_GAP_SECONDS + ); + }; + const chartSampleCount = () => chartSamples.length === 1 ? "1 sample" @@ -1007,6 +1017,10 @@ const appendChartSample = (epoch, metrics) => { if (!Number.isFinite(epoch) || epoch <= 0) return; + if (hasHistoryBackfillGap(epoch)) { + requestHistoryRefresh(); + return; + } const sample = { epoch, metrics: metrics || {} }; const last = chartSamples[chartSamples.length - 1]; if (last && epoch <= last.epoch) { @@ -1019,6 +1033,18 @@ renderAllCharts(); }; + const requestHistoryRefresh = ({ force = false } = {}) => { + if (historyRefreshPromise !== null && !force) { + return historyRefreshPromise; + } + const promise = syncHistory(); + historyRefreshPromise = promise; + promise.finally(() => { + if (historyRefreshPromise === promise) historyRefreshPromise = null; + }); + return promise; + }; + async function syncHistory() { const requestId = (historyRequestId += 1); const seconds = historySeconds(); @@ -1074,7 +1100,7 @@ chartXRange = null; setActiveHistoryRange(historyButton(historyRange)); if (updateUrl) replaceUrlHistoryRange(historyRange); - if (sync) syncHistory(); + if (sync) requestHistoryRefresh({ force: true }); }; const initHistoryRange = () => { @@ -1300,14 +1326,34 @@ ); } + const refreshAfterForeground = () => { + if (document.visibilityState === "hidden") return; + startPolling(); + requestHistoryRefresh(); + tick(); + }; + + const startPolling = () => { + if (timer === null) timer = setInterval(tick, POLL_MS); + }; + + const stopPolling = () => { + if (timer === null) return; + clearInterval(timer); + timer = null; + }; + initEndpointButtons(); initHistoryRange(); - syncHistory(); + requestHistoryRefresh({ force: true }); tick(); - timer = setInterval(tick, POLL_MS); - window.addEventListener("pagehide", () => { - if (timer !== null) clearInterval(timer); + startPolling(); + document.addEventListener("visibilitychange", () => { + if (document.visibilityState === "visible") refreshAfterForeground(); }); + window.addEventListener("focus", refreshAfterForeground); + window.addEventListener("pageshow", refreshAfterForeground); + window.addEventListener("pagehide", stopPolling); })();