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 <noreply@anthropic.com>
This commit is contained in:
33
app.py
33
app.py
@@ -240,13 +240,8 @@ def get_vm_live_stats():
|
|||||||
return live
|
return live
|
||||||
|
|
||||||
|
|
||||||
def get_vm_disk_stats(running_names):
|
def _fetch_disk_stats(running_names):
|
||||||
"""Get filesystem usage for running VMs via virsh guestinfo. Cached for VM_DISK_TTL seconds."""
|
"""Background worker: fetch filesystem stats for all running VMs."""
|
||||||
with _vm_disk_lock:
|
|
||||||
now = time.time()
|
|
||||||
if now - _vm_disk_cache["ts"] < VM_DISK_TTL:
|
|
||||||
return _vm_disk_cache["data"]
|
|
||||||
|
|
||||||
disks = {}
|
disks = {}
|
||||||
for name in running_names:
|
for name in running_names:
|
||||||
try:
|
try:
|
||||||
@@ -256,16 +251,12 @@ def get_vm_disk_stats(running_names):
|
|||||||
)
|
)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
continue
|
continue
|
||||||
# Parse filesystem entries, find root mountpoint
|
|
||||||
fs = {}
|
fs = {}
|
||||||
for line in result.stdout.split("\n"):
|
for line in result.stdout.split("\n"):
|
||||||
if ":" not in line:
|
if ":" not in line:
|
||||||
continue
|
continue
|
||||||
key, val = line.split(":", 1)
|
key, val = line.split(":", 1)
|
||||||
key = key.strip()
|
fs[key.strip()] = val.strip()
|
||||||
val = val.strip()
|
|
||||||
fs[key] = val
|
|
||||||
# Collect all filesystems
|
|
||||||
count = int(fs.get("fs.count", 0))
|
count = int(fs.get("fs.count", 0))
|
||||||
vm_disks = []
|
vm_disks = []
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
@@ -282,11 +273,23 @@ def get_vm_disk_stats(running_names):
|
|||||||
disks[name] = vm_disks
|
disks[name] = vm_disks
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with _vm_disk_lock:
|
with _vm_disk_lock:
|
||||||
_vm_disk_cache["data"] = disks
|
_vm_disk_cache["data"] = disks
|
||||||
_vm_disk_cache["ts"] = time.time()
|
_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():
|
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:
|
try:
|
||||||
req = urllib.request.Request(url.rstrip("/") + "/api/stats")
|
req = urllib.request.Request(url.rstrip("/") + "/api/stats")
|
||||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||||
|
|||||||
Reference in New Issue
Block a user