mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 22:03:13 -06:00
The debug block exposed only gauges (buckets, quarantined, inFlight) — state, not work.
A real flapping Firestick reads as flap.buckets:36, quarantined:0, indistinguishable
from healthy. Add lightweight in-memory throughput counters (total + last-completed
rolling window) so the server tells the flapper/flood story itself.
- lib/rolling-counter.js: shared bounded scalar counter (total, curWindow, lastWindow,
windowStart); rolls lazily on bump AND read (no timer), idle decays to 0.
DEBUG_STATS_WINDOW_MS default 60000.
- flap-limiter: refused{Total,LastWindow} (every allow:false), quarantineStarts{Total,
LastWindow} (a quarantine event stays visible after the gauge decays).
- ota-breaker: stats() rateBackoff{Total,LastWindow}.
- ota-download-guard: servedTotal/shedTotal alongside the per-window values.
- database: maintenance sweepsTotal (confirm the prune is firing, not stalled).
- routes/status: debug block gains ota_breaker + the new fields (aggregate-only, cheap).
Tests: rolling-counter window-roll + idle decay; each counter increments on the right
event; booted /api/status asserts the new fields present + numeric. Suite 285/285.
Fallout doc: observability section lists the fields + what each tells a soak-watcher.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
32 lines
1.3 KiB
JavaScript
32 lines
1.3 KiB
JavaScript
'use strict';
|
|
// #146 observability — a scalar THROUGHPUT counter with a fixed rolling window. Bounded
|
|
// (four ints, no per-key map, no timer): the window rolls lazily on bump AND on read, so
|
|
// an idle subsystem's `lastWindow` correctly decays to the last COMPLETED window (or 0 if
|
|
// two+ windows passed with no activity) without a background timer. Shared so the roll
|
|
// logic is identical everywhere.
|
|
|
|
const config = require('../config');
|
|
|
|
function rollingCounter(windowMs = config.debugStatsWindowMs) {
|
|
return { total: 0, curWindow: 0, lastWindow: 0, windowStart: 0, windowMs };
|
|
}
|
|
|
|
// Roll if the current window has elapsed. First touch just anchors windowStart.
|
|
function roll(c, now) {
|
|
if (c.windowStart === 0) { c.windowStart = now; return; }
|
|
const elapsed = now - c.windowStart;
|
|
if (elapsed >= c.windowMs) {
|
|
// exactly one window closed -> lastWindow is what accumulated; 2+ -> last completed was empty
|
|
c.lastWindow = elapsed < 2 * c.windowMs ? c.curWindow : 0;
|
|
c.curWindow = 0;
|
|
c.windowStart = now;
|
|
}
|
|
}
|
|
|
|
function bump(c, now = Date.now(), n = 1) { roll(c, now); c.curWindow += n; c.total += n; }
|
|
|
|
// Plain, cheap read: { total, lastWindow } (rolls first so idle reads are accurate).
|
|
function read(c, now = Date.now()) { roll(c, now); return { total: c.total, lastWindow: c.lastWindow }; }
|
|
|
|
module.exports = { rollingCounter, bump, read };
|