@@ -253,6 +253,7 @@ async fn main() -> std::io::Result<()> {
253253 containers:: lxc_autostart_all ( ) ;
254254 networking:: apply_all_wireguard_bridges ( ) ;
255255 kubernetes:: apply_all_wolfnet_routes ( ) ;
256+ plugins:: start_all_backends ( ) ;
256257 } ) ;
257258
258259 // Check if TLS will be available (so the frontend knows the correct protocol for URLs)
@@ -331,27 +332,27 @@ async fn main() -> std::io::Result<()> {
331332 tokio:: spawn ( async move {
332333 loop {
333334 tokio:: time:: sleep ( Duration :: from_secs ( 2 ) ) . await ;
334- let ( metrics, components) = {
335- let mut monitor = state_clone. monitor . lock ( ) . unwrap ( ) ;
336- let m = monitor. collect ( ) ;
337- let c = installer:: get_all_status_cached ( ) ;
338- ( m, c)
339- } ;
335+ // Run all blocking sysinfo/subprocess work off the async runtime
336+ let sc = state_clone. clone ( ) ;
337+ let ( metrics, components, docker_count, lxc_count, vm_count, has_docker, has_lxc, has_kvm) =
338+ tokio:: task:: spawn_blocking ( move || {
339+ let mut monitor = sc. monitor . lock ( ) . unwrap ( ) ;
340+ let m = monitor. collect ( ) ;
341+ drop ( monitor) ; // release mutex before spawning subprocesses
342+ let c = installer:: get_all_status_cached ( ) ;
343+ let dc = containers:: docker_count ( ) ;
344+ let lc = containers:: lxc_count ( ) ;
345+ let vc = sc. vms . lock ( ) . unwrap ( ) . list_vms ( ) . len ( ) as u32 ;
346+ let hd = containers:: has_docker_cached ( ) ;
347+ let hl = containers:: has_lxc_cached ( ) ;
348+ let hk = containers:: has_kvm_cached ( ) ;
349+ ( m, c, dc, lc, vc, hd, hl, hk)
350+ } ) . await . unwrap ( ) ;
340351 // Record historical snapshot
341352 {
342353 let mut history = state_clone. metrics_history . lock ( ) . unwrap ( ) ;
343354 history. push ( & metrics) ;
344355 }
345- // Use lightweight counts (1 subprocess each) instead of full listing
346- // (which spawns 3+ subprocesses per container for docker inspect)
347- let docker_count = containers:: docker_count ( ) ;
348- let lxc_count = containers:: lxc_count ( ) ;
349- let vm_count = state_clone. vms . lock ( ) . unwrap ( ) . list_vms ( ) . len ( ) as u32 ;
350- // Use cached runtime detection (TTL 120s) instead of spawning
351- // 'which', 'docker info', etc. on every 2-second cycle
352- let has_docker = containers:: has_docker_cached ( ) ;
353- let has_lxc = containers:: has_lxc_cached ( ) ;
354- let has_kvm = containers:: has_kvm_cached ( ) ;
355356
356357 // Cache the agent status report for instant polling responses
357358 let self_id = cluster_clone. self_id . clone ( ) ;
@@ -508,7 +509,10 @@ async fn main() -> std::io::Result<()> {
508509 let mut all_issues: Vec < ( String , String , api:: Issue ) > = Vec :: new ( ) ;
509510
510511 // Local node
511- let metrics = scan_state. monitor . lock ( ) . unwrap ( ) . collect ( ) ;
512+ let ss = scan_state. clone ( ) ;
513+ let metrics = tokio:: task:: spawn_blocking ( move || {
514+ ss. monitor . lock ( ) . unwrap ( ) . collect ( )
515+ } ) . await . unwrap ( ) ;
512516 let local_hostname = metrics. hostname . clone ( ) ;
513517 let local_cluster = {
514518 let nodes = scan_cluster. get_all_nodes ( ) ;
@@ -1103,24 +1107,26 @@ a{color:#dc2626;text-decoration:none;}a:hover{text-decoration:underline;}
11031107
11041108 if is_configured {
11051109 // Collect local metrics (sync — release mutex before any .await)
1110+ let ai_sc = ai_state. clone ( ) ;
11061111 let ( hostname, cpu_pct, mem_used_gb, mem_total_gb, disk_used_gb, disk_total_gb,
1107- docker_count, lxc_count, vm_count, uptime_secs) = {
1108- let mut monitor = ai_state. monitor . lock ( ) . unwrap ( ) ;
1109- let m = monitor. collect ( ) ;
1110- let docker_count = containers:: docker_count ( ) ;
1111- let lxc_count = containers:: lxc_count ( ) ;
1112- let vm_count = ai_state. vms . lock ( ) . unwrap ( ) . list_vms ( ) . len ( ) as u32 ;
1113-
1114- let mem_used = m. memory_used_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ;
1115- let mem_total = m. memory_total_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ;
1116- let root_disk = m. disks . iter ( ) . find ( |d| d. mount_point == "/" ) . or_else ( || m. disks . first ( ) ) ;
1117- let disk_used = root_disk. map ( |d| d. used_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ) . unwrap_or ( 0.0 ) ;
1118- let disk_total = root_disk. map ( |d| d. total_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ) . unwrap_or ( 0.0 ) ;
1119-
1120- ( m. hostname . clone ( ) , m. cpu_usage_percent , mem_used, mem_total,
1121- disk_used, disk_total, docker_count, lxc_count, vm_count, m. uptime_secs )
1122- } ;
1123- // MutexGuard is now dropped — safe to .await below
1112+ docker_count, lxc_count, vm_count, uptime_secs) =
1113+ tokio:: task:: spawn_blocking ( move || {
1114+ let mut monitor = ai_sc. monitor . lock ( ) . unwrap ( ) ;
1115+ let m = monitor. collect ( ) ;
1116+ drop ( monitor) ;
1117+ let docker_count = containers:: docker_count ( ) ;
1118+ let lxc_count = containers:: lxc_count ( ) ;
1119+ let vm_count = ai_sc. vms . lock ( ) . unwrap ( ) . list_vms ( ) . len ( ) as u32 ;
1120+
1121+ let mem_used = m. memory_used_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ;
1122+ let mem_total = m. memory_total_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ;
1123+ let root_disk = m. disks . iter ( ) . find ( |d| d. mount_point == "/" ) . or_else ( || m. disks . first ( ) ) ;
1124+ let disk_used = root_disk. map ( |d| d. used_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ) . unwrap_or ( 0.0 ) ;
1125+ let disk_total = root_disk. map ( |d| d. total_bytes as f64 / ( 1024.0 * 1024.0 * 1024.0 ) ) . unwrap_or ( 0.0 ) ;
1126+
1127+ ( m. hostname . clone ( ) , m. cpu_usage_percent , mem_used, mem_total,
1128+ disk_used, disk_total, docker_count, lxc_count, vm_count, m. uptime_secs )
1129+ } ) . await . unwrap ( ) ;
11241130
11251131 // Collect per-guest CPU stats from Proxmox nodes in the cluster
11261132 let pve_nodes: Vec < _ > = ai_state. cluster . get_all_nodes ( ) . into_iter ( )
0 commit comments