status: consolidate the pill to one dot + one word; upgrade the panel
- pill: two host dots -> ONE consolidated state (down > slow > up) — the at-a-glance question is 'can I watch?', which is one state; per-host detail belongs in the tap panel - panel: dashed slow-threshold line in the CDN sparkline (drawn at the server's real threshold, not a client copy) + origin up/down step sparkline so 'how long has the origin been down' is visible - server: origin probe keeps a 20-sample hist like the CDN probe; DEGRADED threshold is now ANIWEB_CDN_KBPS (default 40) and is returned in /api/cdn so the UI draws the line at the live value - tests: pill assertions switched to consolidated states; fixtures carry origin hist + threshold; assert both sparklines + threshold line - docs: README + SPEC synced; preview on :8322 restarted (pid 44382)
This commit is contained in:
1 parent
778bf2bfc1
commit
5f7aa010f1
8 files changed
+105
-56
No files matched your search
+8
-3
@@ -48,7 +48,10 @@ VERSION = _version()
|
||||
_CDN = {"state": "unknown", "kbps": 0.0, "ts": 0.0, "hist": []}
|
||||
# origin (primary provider pages/API) health — separate host, separate failure
|
||||
# mode (observed 2026-09-03: CDN fine while origin 503'd "Under Maintenance")
|
||||
_ORIGIN = {"state": "unknown", "msg": "", "ts": 0.0}
|
||||
_ORIGIN = {"state": "unknown", "msg": "", "ts": 0.0, "hist": []}
|
||||
# ponytail: fixed threshold; if the CDN's normal throughput drifts below it
|
||||
# the pill sits on "slow" — tune via ANIWEB_CDN_KBPS, not a percentile.
|
||||
_CDN_THRESHOLD = float(os.environ.get("ANIWEB_CDN_KBPS", "40"))
|
||||
|
||||
|
||||
def _cdn_probe():
|
||||
@@ -81,7 +84,7 @@ def _cdn_probe():
|
||||
kbps = len(r.content) / 1024 / max(time.time() - t, 0.01)
|
||||
except Exception:
|
||||
kbps = 0.0
|
||||
now = "OK" if kbps >= 40 else "DEGRADED"
|
||||
now = "OK" if kbps >= _CDN_THRESHOLD else "DEGRADED"
|
||||
if now != state:
|
||||
print(f"[probe] CDN {now} ({kbps:.0f} KB/s)", flush=True)
|
||||
state = now
|
||||
@@ -103,6 +106,8 @@ def _origin_probe():
|
||||
state, msg = "DOWN", str(e)
|
||||
prev = _ORIGIN["state"]
|
||||
_ORIGIN.update(state=state, msg=msg, ts=time.time())
|
||||
_ORIGIN["hist"].append({"t": time.time(), "state": state})
|
||||
del _ORIGIN["hist"][:-20]
|
||||
if state != prev:
|
||||
print(f"[probe] ORIGIN {state} ({msg})", flush=True)
|
||||
|
||||
@@ -114,7 +119,7 @@ threading.Thread(target=_cdn_probe, daemon=True).start()
|
||||
async def cdn_status():
|
||||
"""CDN + origin health (read-only, public). Top-level fields are the CDN
|
||||
probe (existing shape); .origin is the anidb.app pages/API probe."""
|
||||
return {**_CDN, "origin": _ORIGIN}
|
||||
return {**_CDN, "threshold": _CDN_THRESHOLD, "origin": _ORIGIN}
|
||||
|
||||
# ---------- auth: multi-user, signed cookies ----------
|
||||
users.migrate_legacy() # file-based legacy import; db.init() absorbs its output
|
||||
|
||||
Reference in new issue
Block a user