From e10a57bb6c38b376e1667c768d4360e63371e27d Mon Sep 17 00:00:00 2001 From: kamaji Date: Tue, 24 Feb 2026 22:19:21 -0600 Subject: [PATCH] Fix dashboard timeout by making disk stats non-blocking virsh guestinfo calls (one per VM) took ~4s on cold cache, exceeding the dashboard's 3s fetch timeout. Disk stats now refresh in a background thread and return stale/empty data immediately. Also raised dashboard fetch timeout to 8s for cold-cache dominfo calls. Co-Authored-By: Claude Opus 4.6 --- app.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/app.py b/app.py index a02408a..430fe90 100644 --- a/app.py +++ b/app.py @@ -240,13 +240,8 @@ def get_vm_live_stats(): return live -def get_vm_disk_stats(running_names): - """Get filesystem usage for running VMs via virsh guestinfo. Cached for VM_DISK_TTL seconds.""" - with _vm_disk_lock: - now = time.time() - if now - _vm_disk_cache["ts"] < VM_DISK_TTL: - return _vm_disk_cache["data"] - +def _fetch_disk_stats(running_names): + """Background worker: fetch filesystem stats for all running VMs.""" disks = {} for name in running_names: try: @@ -256,16 +251,12 @@ def get_vm_disk_stats(running_names): ) if result.returncode != 0: continue - # Parse filesystem entries, find root mountpoint fs = {} for line in result.stdout.split("\n"): if ":" not in line: continue key, val = line.split(":", 1) - key = key.strip() - val = val.strip() - fs[key] = val - # Collect all filesystems + fs[key.strip()] = val.strip() count = int(fs.get("fs.count", 0)) vm_disks = [] for i in range(count): @@ -282,11 +273,23 @@ def get_vm_disk_stats(running_names): disks[name] = vm_disks except Exception: continue - with _vm_disk_lock: _vm_disk_cache["data"] = disks _vm_disk_cache["ts"] = time.time() - return disks + _vm_disk_cache["refreshing"] = False + + +def get_vm_disk_stats(running_names): + """Get filesystem usage. Returns cached data immediately; refreshes in background.""" + with _vm_disk_lock: + now = time.time() + stale = now - _vm_disk_cache["ts"] >= VM_DISK_TTL + refreshing = _vm_disk_cache.get("refreshing", False) + if stale and not refreshing: + _vm_disk_cache["refreshing"] = True + t = threading.Thread(target=_fetch_disk_stats, args=(running_names,), daemon=True) + t.start() + return _vm_disk_cache["data"] def get_vm_base_info(): @@ -380,7 +383,7 @@ def get_local_stats(): } -def fetch_remote_stats(url, timeout=3): +def fetch_remote_stats(url, timeout=8): try: req = urllib.request.Request(url.rstrip("/") + "/api/stats") with urllib.request.urlopen(req, timeout=timeout) as resp: