From a2519b2814261b1d76ae7a8c0c59566673df19c3 Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Tue, 28 Oct 2025 10:48:29 +0100 Subject: [PATCH] Update version to 0.1.20 and fix email notification aggregation - Fix email notification aggregation to send batched notifications instead of individual emails - Fix startup data collection to properly process initial status without triggering change notifications - Maintain event-driven transmission while preserving aggregated notification batching - Update version from 0.1.19 to 0.1.20 across all components --- agent/Cargo.toml | 2 +- agent/src/agent.rs | 2 +- agent/src/status/mod.rs | 69 ++++++++++++++++------------------------- dashboard/Cargo.toml | 2 +- dashboard/src/main.rs | 2 +- shared/Cargo.toml | 2 +- 6 files changed, 31 insertions(+), 48 deletions(-) diff --git a/agent/Cargo.toml b/agent/Cargo.toml index 243b710..b5273e4 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-agent" -version = "0.1.19" +version = "0.1.20" edition = "2021" [dependencies] diff --git a/agent/src/agent.rs b/agent/src/agent.rs index b126ffe..04d3fbc 100644 --- a/agent/src/agent.rs +++ b/agent/src/agent.rs @@ -125,7 +125,7 @@ impl Agent { info!("Force collected and cached {} metrics", metrics.len()); - // Process metrics through status manager (don't trigger transmission on startup) + // Process metrics through status manager (collect status data at startup) let _status_changed = self.process_metrics(&metrics).await; Ok(()) diff --git a/agent/src/status/mod.rs b/agent/src/status/mod.rs index ea1a074..20af9ba 100644 --- a/agent/src/status/mod.rs +++ b/agent/src/status/mod.rs @@ -158,62 +158,45 @@ impl HostStatusManager { - /// Process a metric - updates status and triggers immediate notifications if status changed - pub async fn process_metric(&mut self, metric: &Metric, notification_manager: &mut crate::notifications::NotificationManager) -> bool { - let old_status = self.service_statuses.get(&metric.name).copied().unwrap_or(Status::Unknown); + /// Process a metric - updates status and queues for aggregated notifications if status changed + pub async fn process_metric(&mut self, metric: &Metric, _notification_manager: &mut crate::notifications::NotificationManager) -> bool { + let old_status = self.service_statuses.get(&metric.name).copied(); let new_status = metric.status; // Update status self.update_service_status(metric.name.clone(), new_status); - // Check if status actually changed - if old_status != new_status { - debug!("Status change detected for {}: {:?} -> {:?}", metric.name, old_status, new_status); - - // Process notification immediately on status change - if let Err(e) = self.process_status_change(&metric.name, old_status, new_status, notification_manager).await { - error!("Failed to process status change notification: {}", e); + // Check if status actually changed (ignore first-time status setting) + if let Some(old_status) = old_status { + if old_status != new_status { + debug!("Status change detected for {}: {:?} -> {:?}", metric.name, old_status, new_status); + + // Queue change for aggregated notification (not immediate) + self.queue_status_change(&metric.name, old_status, new_status); + + return true; // Status changed - caller should trigger immediate transmission } - - return true; // Status changed - caller should trigger immediate transmission + } else { + debug!("Initial status set for {}: {:?}", metric.name, new_status); } - false // No status change + false // No status change (or first-time status) } - /// Process immediate status change notification - async fn process_status_change(&mut self, metric_name: &str, old_status: Status, new_status: Status, notification_manager: &mut crate::notifications::NotificationManager) -> Result<(), Box> { - if !self.config.enabled { - return Ok(()); - } - - // Create immediate notification for this specific status change - let status_summary = StatusChangeSummary { - service_name: metric_name.to_string(), - initial_status: old_status, - final_status: new_status, - change_count: 1, - }; - - let aggregated = AggregatedStatusChanges { - start_time: Instant::now(), - end_time: Instant::now(), - service_summaries: vec![status_summary], - host_status_initial: old_status, - host_status_final: new_status, - requires_notification: true, - }; - - // Send immediate notification using existing method - if let Err(e) = self.send_aggregated_email(&aggregated, notification_manager).await { - error!("Failed to send immediate notification: {}", e); - return Err(e); - } + /// Queue status change for aggregated notification + fn queue_status_change(&mut self, metric_name: &str, old_status: Status, new_status: Status) { + // Add to pending changes for aggregated notification + let entry = self.pending_changes.entry(metric_name.to_string()).or_insert((old_status, old_status, 0)); + entry.1 = new_status; // Update final status + entry.2 += 1; // Increment change count - info!("Sent immediate notification for {} status change: {:?} -> {:?}", metric_name, old_status, new_status); - Ok(()) + // Set batch start time if this is the first change + if self.batch_start_time.is_none() { + self.batch_start_time = Some(Instant::now()); + } } + /// Process pending notifications - legacy method, now rarely used pub async fn process_pending_notifications(&mut self, notification_manager: &mut crate::notifications::NotificationManager) -> Result<(), Box> { if !self.config.enabled || self.pending_changes.is_empty() { diff --git a/dashboard/Cargo.toml b/dashboard/Cargo.toml index e9f41ab..8ce6949 100644 --- a/dashboard/Cargo.toml +++ b/dashboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard" -version = "0.1.19" +version = "0.1.20" edition = "2021" [dependencies] diff --git a/dashboard/src/main.rs b/dashboard/src/main.rs index 8ecf9cb..adfe80f 100644 --- a/dashboard/src/main.rs +++ b/dashboard/src/main.rs @@ -14,7 +14,7 @@ use app::Dashboard; /// Get hardcoded version fn get_version() -> &'static str { - "v0.1.19" + "v0.1.20" } /// Check if running inside tmux session diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 7024479..9890e42 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-shared" -version = "0.1.19" +version = "0.1.20" edition = "2021" [dependencies]