From d32420c6f67c6d9d6dd4fa1befeb70723383b8da Mon Sep 17 00:00:00 2001 From: Cylae <13425054+Cylae@users.noreply.github.com> Date: Sat, 14 Feb 2026 13:35:18 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Optimize=20dashboard=20system=20sta?= =?UTF-8?q?ts=20refresh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Offloaded blocking `sysinfo` refresh methods and mutex locking in the `dashboard` handler to `tokio::task::spawn_blocking`. This prevents the async executor threads from being stalled by potentially slow operations such as disk enumeration, which is a critical performance fix for maintaining responsiveness of the Web UI under heavy system load or when dealing with slow hardware. The optimization: - Moves `system.lock()` and `last_system_refresh.lock()` into the blocking task. - Wraps `sys.refresh_cpu()`, `sys.refresh_memory()`, and `sys.refresh_disks()` in `spawn_blocking`. - Extracts all necessary metrics within the blocking task and returns them as a tuple. - Ensures the `AppState` is properly shared via `Arc`. --- server_manager/src/interface/web.rs | 85 ++++++++++++++++------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/server_manager/src/interface/web.rs b/server_manager/src/interface/web.rs index 1f677c3..9bfd52f 100644 --- a/server_manager/src/interface/web.rs +++ b/server_manager/src/interface/web.rs @@ -330,44 +330,53 @@ async fn dashboard(State(state): State, session: Session) -> impl I let services = services::get_all_services(); let config = state.get_config().await; - // System Stats - let mut sys = state.system.lock().unwrap(); - let now = SystemTime::now(); - let mut last_refresh = state.last_system_refresh.lock().unwrap(); - - // Throttle refresh to max once every 500ms - if now - .duration_since(*last_refresh) - .unwrap_or_default() - .as_millis() - > 500 - { - sys.refresh_cpu(); - sys.refresh_memory(); - sys.refresh_disks(); - *last_refresh = now; - } - let ram_used = sys.used_memory() / 1024 / 1024; // MB - let ram_total = sys.total_memory() / 1024 / 1024; // MB - let swap_used = sys.used_swap() / 1024 / 1024; // MB - let swap_total = sys.total_swap() / 1024 / 1024; // MB - let cpu_usage = sys.global_cpu_info().cpu_usage(); - - // Simple Disk Usage (Root or fallback) - let mut disk_total = 0; - let mut disk_used = 0; - - let target_disk = sys - .disks() - .iter() - .find(|d| d.mount_point() == std::path::Path::new("/")) - .or_else(|| sys.disks().first()); - - if let Some(disk) = target_disk { - disk_total = disk.total_space() / 1024 / 1024 / 1024; // GB - disk_used = (disk.total_space() - disk.available_space()) / 1024 / 1024 / 1024; // GB - } - drop(sys); // Release lock explicitely + // System Stats - Offload blocking refresh to a separate thread + let state_clone = Arc::clone(&state); + let (cpu_usage, ram_used, ram_total, swap_used, swap_total, disk_used, disk_total) = + tokio::task::spawn_blocking(move || { + let mut sys = state_clone.system.lock().unwrap(); + let now = SystemTime::now(); + let mut last_refresh = state_clone.last_system_refresh.lock().unwrap(); + + // Throttle refresh to max once every 500ms + if now + .duration_since(*last_refresh) + .unwrap_or_default() + .as_millis() + > 500 + { + sys.refresh_cpu(); + sys.refresh_memory(); + sys.refresh_disks(); + *last_refresh = now; + } + let ram_used = sys.used_memory() / 1024 / 1024; // MB + let ram_total = sys.total_memory() / 1024 / 1024; // MB + let swap_used = sys.used_swap() / 1024 / 1024; // MB + let swap_total = sys.total_swap() / 1024 / 1024; // MB + let cpu_usage = sys.global_cpu_info().cpu_usage(); + + // Simple Disk Usage (Root or fallback) + let mut disk_total = 0; + let mut disk_used = 0; + + let target_disk = sys + .disks() + .iter() + .find(|d| d.mount_point() == std::path::Path::new("/")) + .or_else(|| sys.disks().first()); + + if let Some(disk) = target_disk { + disk_total = disk.total_space() / 1024 / 1024 / 1024; // GB + disk_used = (disk.total_space() - disk.available_space()) / 1024 / 1024 / 1024; // GB + } + + ( + cpu_usage, ram_used, ram_total, swap_used, swap_total, disk_used, disk_total, + ) + }) + .await + .unwrap_or((0.0, 0, 0, 0, 0, 0, 0)); let mut html = String::with_capacity(8192); write_html_head(&mut html, "Dashboard - Server Manager");