From f016c2bae083193cd55ae47617296c8eb69237a8 Mon Sep 17 00:00:00 2001 From: kodi Date: Sun, 22 Mar 2026 15:09:53 +0100 Subject: [PATCH] perf: stats poll via lichtgewicht /api/stats i.p.v. /containers-dashboard De frontend haalde CPU/mem stats op via het zware /containers-dashboard endpoint (Podman call + os.walk + systemctl subprocesses per container). Nu gaat de stats poll via een nieuw /api/stats endpoint dat alleen de bestaande in-memory cache teruggeeft (<5ms vs ~400ms). - app_containers.py: /api/stats endpoint toegevoegd (cache direct return) - app_containers.py: _STATS_SHOWN_NAMES bijgehouden per dashboard call (filtert infra/management containers eruit op basis van _dashboard_source) - containers.js: pollContainersDashboardStatsOnce() gebruikt /api/stats Co-Authored-By: Claude Sonnet 4.6 --- control/app_containers.py | 16 ++++++++++++++++ webui/html/assets/js/tabs/containers.js | 18 +++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/control/app_containers.py b/control/app_containers.py index 2092c9d..a7a2f2d 100644 --- a/control/app_containers.py +++ b/control/app_containers.py @@ -30,6 +30,7 @@ _PODMAN_API_BASE = None _STATS_CACHE_BY_NAME = {} # name -> {"cpu": float|None, "mem_usage": float|None, "mem_perc": float|None} _STATS_CACHE_TS = None _STATS_POLLER_TASK = None +_STATS_SHOWN_NAMES: set = set() # namen van systemd-managed containers uit laatste dashboard call # --- EXEC SESSION CACHE (in-memory) --- _EXEC_SESSIONS = {} # session_id -> _ExecSessionState @@ -478,8 +479,23 @@ def init_containers_router( row["Status"] = (out or "").strip() dashboard.append(row) + # Bijwerken welke namen systemd-managed zijn (voor /stats filter) + global _STATS_SHOWN_NAMES + _STATS_SHOWN_NAMES = { + _norm_container_name((c.get("Names") or ["?"])[0]) + for c in dashboard + if c.get("_dashboard_source") == "systemd" + } - {"?", ""} + return dashboard + @router.get("/stats") + def stats_snapshot(): + cache = _STATS_CACHE_BY_NAME + if _STATS_SHOWN_NAMES: + return {k: v for k, v in cache.items() if k in _STATS_SHOWN_NAMES} + return cache + @router.get("/containers") def list_containers(): # Ook hier ?all=true voor gestopte containers diff --git a/webui/html/assets/js/tabs/containers.js b/webui/html/assets/js/tabs/containers.js index 4538226..8ba4f29 100644 --- a/webui/html/assets/js/tabs/containers.js +++ b/webui/html/assets/js/tabs/containers.js @@ -261,27 +261,19 @@ async function pollContainersDashboardStatsOnce() { if (containersDashboardStatsInFlight) return; containersDashboardStatsInFlight = true; try { - const containers = await api('/containers-dashboard', 'GET'); - const list = Array.isArray(containers) ? containers : (containers?.containers || []); + const stats = await api('/stats', 'GET'); // totals per pod voor deze poll tick const podCpu = new Map(); // podName -> cpuPct sum const podMem = new Map(); // podName -> memBytes sum const podMemPct = new Map(); // podName -> memPct sum - for (const c of (list || [])) { - const cname = normalizeContainerName((c?.Names && c.Names[0]) ? c.Names[0] : (c?.Names || c?.Name || c?.name || '')); - if (!cname) continue; - + for (const [cname, s] of Object.entries(stats || {})) { const key = cssSafeId(cname); - const cpuRaw = c?._dashboard_cpu; - const memBytesRaw = c?._dashboard_mem_usage; - const memPctRaw = c?._dashboard_mem_perc; - - const cpuPct = Number(cpuRaw); - const memBytes = Number(memBytesRaw); - const memPct = Number(memPctRaw); + const cpuPct = Number(s?.cpu); + const memBytes = Number(s?.mem_usage); + const memPct = Number(s?.mem_perc); const pod = containersC2P.get(cname); if (pod) {