From ad1fcaa27b362ce108b50d7209a842e73e52e0b8 Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Mon, 1 Dec 2025 13:03:45 +0100 Subject: [PATCH] Fix collector interval timing to prevent excessive SMART checks Collectors now respect their configured intervals instead of running every transmission cycle (2s). This prevents disk SMART checks from running every 2 seconds, which was causing constant disk activity. - Add TimedCollector wrapper with interval tracking - Only collect from collectors whose interval has elapsed - Disk collector now properly runs every 300s instead of every 2s - Bump version to v0.1.229 --- Cargo.lock | 6 +-- agent/Cargo.toml | 2 +- agent/src/agent.rs | 108 ++++++++++++++++++++++++++++++++++--------- dashboard/Cargo.toml | 2 +- shared/Cargo.toml | 2 +- 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 459526f..ccdf7f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cm-dashboard" -version = "0.1.227" +version = "0.1.229" dependencies = [ "anyhow", "chrono", @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "cm-dashboard-agent" -version = "0.1.227" +version = "0.1.229" dependencies = [ "anyhow", "async-trait", @@ -325,7 +325,7 @@ dependencies = [ [[package]] name = "cm-dashboard-shared" -version = "0.1.227" +version = "0.1.229" dependencies = [ "chrono", "serde", diff --git a/agent/Cargo.toml b/agent/Cargo.toml index 958fe0b..1ee89f7 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-agent" -version = "0.1.228" +version = "0.1.229" edition = "2021" [dependencies] diff --git a/agent/src/agent.rs b/agent/src/agent.rs index dade4c5..d57d607 100644 --- a/agent/src/agent.rs +++ b/agent/src/agent.rs @@ -1,6 +1,6 @@ use anyhow::Result; use gethostname::gethostname; -use std::time::Duration; +use std::time::{Duration, Instant}; use tokio::time::interval; use tracing::{debug, error, info}; @@ -19,11 +19,19 @@ use crate::collectors::{ use crate::notifications::NotificationManager; use cm_dashboard_shared::AgentData; +/// Wrapper for collectors with timing information +struct TimedCollector { + collector: Box, + interval: Duration, + last_collection: Option, + name: String, +} + pub struct Agent { hostname: String, config: AgentConfig, zmq_handler: ZmqHandler, - collectors: Vec>, + collectors: Vec, notification_manager: NotificationManager, previous_status: Option, } @@ -55,36 +63,78 @@ impl Agent { config.zmq.publisher_port ); - // Initialize collectors - let mut collectors: Vec> = Vec::new(); - + // Initialize collectors with timing information + let mut collectors: Vec = Vec::new(); + // Add enabled collectors if config.collectors.cpu.enabled { - collectors.push(Box::new(CpuCollector::new(config.collectors.cpu.clone()))); + collectors.push(TimedCollector { + collector: Box::new(CpuCollector::new(config.collectors.cpu.clone())), + interval: Duration::from_secs(config.collectors.cpu.interval_seconds), + last_collection: None, + name: "CPU".to_string(), + }); + info!("CPU collector initialized with {}s interval", config.collectors.cpu.interval_seconds); } - + if config.collectors.memory.enabled { - collectors.push(Box::new(MemoryCollector::new(config.collectors.memory.clone()))); + collectors.push(TimedCollector { + collector: Box::new(MemoryCollector::new(config.collectors.memory.clone())), + interval: Duration::from_secs(config.collectors.memory.interval_seconds), + last_collection: None, + name: "Memory".to_string(), + }); + info!("Memory collector initialized with {}s interval", config.collectors.memory.interval_seconds); } - + if config.collectors.disk.enabled { - collectors.push(Box::new(DiskCollector::new(config.collectors.disk.clone()))); + collectors.push(TimedCollector { + collector: Box::new(DiskCollector::new(config.collectors.disk.clone())), + interval: Duration::from_secs(config.collectors.disk.interval_seconds), + last_collection: None, + name: "Disk".to_string(), + }); + info!("Disk collector initialized with {}s interval", config.collectors.disk.interval_seconds); } - + if config.collectors.systemd.enabled { - collectors.push(Box::new(SystemdCollector::new(config.collectors.systemd.clone()))); + collectors.push(TimedCollector { + collector: Box::new(SystemdCollector::new(config.collectors.systemd.clone())), + interval: Duration::from_secs(config.collectors.systemd.interval_seconds), + last_collection: None, + name: "Systemd".to_string(), + }); + info!("Systemd collector initialized with {}s interval", config.collectors.systemd.interval_seconds); } - + if config.collectors.backup.enabled { - collectors.push(Box::new(BackupCollector::new())); + collectors.push(TimedCollector { + collector: Box::new(BackupCollector::new()), + interval: Duration::from_secs(config.collectors.backup.interval_seconds), + last_collection: None, + name: "Backup".to_string(), + }); + info!("Backup collector initialized with {}s interval", config.collectors.backup.interval_seconds); } if config.collectors.network.enabled { - collectors.push(Box::new(NetworkCollector::new(config.collectors.network.clone()))); + collectors.push(TimedCollector { + collector: Box::new(NetworkCollector::new(config.collectors.network.clone())), + interval: Duration::from_secs(config.collectors.network.interval_seconds), + last_collection: None, + name: "Network".to_string(), + }); + info!("Network collector initialized with {}s interval", config.collectors.network.interval_seconds); } if config.collectors.nixos.enabled { - collectors.push(Box::new(NixOSCollector::new(config.collectors.nixos.clone()))); + collectors.push(TimedCollector { + collector: Box::new(NixOSCollector::new(config.collectors.nixos.clone())), + interval: Duration::from_secs(config.collectors.nixos.interval_seconds), + last_collection: None, + name: "NixOS".to_string(), + }); + info!("NixOS collector initialized with {}s interval", config.collectors.nixos.interval_seconds); } info!("Initialized {} collectors", collectors.len()); @@ -152,11 +202,27 @@ impl Agent { // Initialize empty AgentData let mut agent_data = AgentData::new(self.hostname.clone(), env!("CARGO_PKG_VERSION").to_string()); - // Collect data from all collectors - for collector in &self.collectors { - if let Err(e) = collector.collect_structured(&mut agent_data).await { - error!("Collector failed: {}", e); - // Continue with other collectors even if one fails + // Collect data from collectors whose intervals have elapsed + let now = Instant::now(); + for timed_collector in &mut self.collectors { + let should_collect = match timed_collector.last_collection { + None => true, // First collection + Some(last_time) => now.duration_since(last_time) >= timed_collector.interval, + }; + + if should_collect { + if let Err(e) = timed_collector.collector.collect_structured(&mut agent_data).await { + error!("Collector {} failed: {}", timed_collector.name, e); + // Update last_collection time even on failure to prevent immediate retries + timed_collector.last_collection = Some(now); + } else { + timed_collector.last_collection = Some(now); + debug!( + "Collected from {} ({}s interval)", + timed_collector.name, + timed_collector.interval.as_secs() + ); + } } } diff --git a/dashboard/Cargo.toml b/dashboard/Cargo.toml index a704050..4b6aae2 100644 --- a/dashboard/Cargo.toml +++ b/dashboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard" -version = "0.1.228" +version = "0.1.229" edition = "2021" [dependencies] diff --git a/shared/Cargo.toml b/shared/Cargo.toml index f47a973..31354d4 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-shared" -version = "0.1.228" +version = "0.1.229" edition = "2021" [dependencies]