From a4a5a8e3f29e9f1418332115f09b024408dc02d3 Mon Sep 17 00:00:00 2001 From: Carsten Rehfeld Date: Sun, 17 May 2026 01:37:55 +0200 Subject: [PATCH] =?UTF-8?q?fix(admin):=20sliding-window=20rate=20=E2=80=94?= =?UTF-8?q?=20no=20sawtooth=20drop=20at=20bucket=20boundaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace fixed-window accDelta (resets to 0 every 5 s) with a sliding window: recentPolls[] holds {t, delta} entries; liveRpm() sums all entries within the last 5 s and extrapolates to rpm. Old entries age out naturally so the rate decays smoothly with no hard reset jump. Chart and label now update continuously without the 0-drop artifact. Co-Authored-By: Mira Rehfeld --- .../resources/META-INF/resources/admin.js | 37 +++++++++---------- .../templates/DashboardResource/global.html | 2 +- .../templates/DashboardResource/sandbox.html | 2 +- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/apix-admin/src/main/resources/META-INF/resources/admin.js b/apix-admin/src/main/resources/META-INF/resources/admin.js index e64366b..1cb0f27 100644 --- a/apix-admin/src/main/resources/META-INF/resources/admin.js +++ b/apix-admin/src/main/resources/META-INF/resources/admin.js @@ -147,11 +147,9 @@ var buf = new Array(BUCKETS).fill(0); var lastTotal = null; - var accDelta = 0; // accumulated since last chart flush - var lastActivity = Date.now(); // time of last non-zero delta + var lastActivity = Date.now(); var currentInterval = FAST_INTERVAL; - var lastFlushTime = Date.now(); - var lastWindowRpm = 0; // rate from previous flush window + var recentPolls = []; // {t, delta} — sliding window entries var ML = 36, MB = 18; var W = el.parentElement.clientWidth || 900; @@ -206,25 +204,25 @@ if (elLive) elLive.textContent = fmt(rpm) + ' req/min (' + pct + '%)'; } - // Compute the current in-progress bucket value (capped at rateLimit) + // Sliding-window rate: sum of deltas in the last CHART_TICK ms, extrapolated to rpm. + // No hard reset at bucket boundaries — rate transitions are smooth. function liveRpm() { - var windowMs = Math.max(Date.now() - lastFlushTime, 1); - return Math.min(Math.round(accDelta * (60000 / windowMs)), rateLimit); + var now = Date.now(); + var cutoff = now - CHART_TICK; + while (recentPolls.length && recentPolls[0].t < cutoff) recentPolls.shift(); + var sum = recentPolls.reduce(function (s, e) { return s + e.delta; }, 0); + return Math.min(Math.round(sum * (60000 / CHART_TICK)), rateLimit); } - // Redraw: historical buf + current live bucket at the right edge ("now") + // Redraw: historical buf + live bucket at the right edge function redraw() { var view = buf.slice(1).concat([liveRpm()]); path.attr('d', areaFn(view)); } - // Every 5 s: commit the current bucket into buf, reset accumulator + // Every 5 s: snapshot the current sliding-window rate into the history buffer setInterval(function () { - var rpm = liveRpm(); - lastWindowRpm = rpm; - lastFlushTime = Date.now(); - buf.push(rpm); buf.shift(); - accDelta = 0; + buf.push(liveRpm()); buf.shift(); }, CHART_TICK); async function poll() { @@ -235,12 +233,13 @@ var total = Number(d.totalRequests) || 0; if (lastTotal !== null) { var delta = Math.max(0, total - lastTotal); - accDelta += delta; - if (delta > 0) lastActivity = Date.now(); - var windowMs = Date.now() - lastFlushTime; - var rpm = windowMs > 200 ? liveRpm() : lastWindowRpm; + if (delta > 0) { + recentPolls.push({t: Date.now(), delta: delta}); + lastActivity = Date.now(); + } + var rpm = liveRpm(); updateLabel(rpm); - redraw(); // update chart on every poll, not just every 5 s + redraw(); } lastTotal = total; currentInterval = (Date.now() - lastActivity > IDLE_AFTER_MS) ? IDLE_INTERVAL : FAST_INTERVAL; diff --git a/apix-admin/src/main/resources/templates/DashboardResource/global.html b/apix-admin/src/main/resources/templates/DashboardResource/global.html index 41fcd20..ce8e6d7 100644 --- a/apix-admin/src/main/resources/templates/DashboardResource/global.html +++ b/apix-admin/src/main/resources/templates/DashboardResource/global.html @@ -106,6 +106,6 @@ nav { - + diff --git a/apix-admin/src/main/resources/templates/DashboardResource/sandbox.html b/apix-admin/src/main/resources/templates/DashboardResource/sandbox.html index 302c8f6..b025445 100644 --- a/apix-admin/src/main/resources/templates/DashboardResource/sandbox.html +++ b/apix-admin/src/main/resources/templates/DashboardResource/sandbox.html @@ -151,6 +151,6 @@ button.promote:hover { background: #2ea043; } - +