//! latency alert/recovery messages. Domain half of the Alerter split; //! shared dispatch/cooldown plumbing lives in the parent module. use tracing::instrument; use super::{AlertCategory, AlertMeta, Alerter}; impl Alerter { #[instrument(skip_all)] pub async fn send_latency_drift_alert(&self, target: &str, label: &str, drift_message: &str) { let alert_key = format!("latency:{target}"); let subject = format!("[PoM] {target}: latency drift detected"); let body = format!( "Target: {label} ({target})\n\ {drift_message}\n\ Instance: {}\n\ Time: {}\n\n\ - PoM", self.instance_name, chrono::Utc::now().to_rfc3339(), ); self.fire_failure( &subject, &body, "medium", "pom-latency", Some(target), AlertMeta { key: &alert_key, category: AlertCategory::LatencyDrift, from: None, to: None, error: Some(drift_message), }, ) .await; } #[instrument(skip_all)] pub async fn send_latency_recovery(&self, target: &str, label: &str) { let alert_key = format!("latency:{target}"); let subject = format!("[PoM] {target}: latency recovered"); let body = format!( "Target: {label} ({target})\n\ Latency returned to normal.\n\ Instance: {}\n\ Time: {}\n\n\ - PoM", self.instance_name, chrono::Utc::now().to_rfc3339(), ); self.fire_recovery( &subject, &body, AlertMeta { key: &alert_key, category: AlertCategory::LatencyRecovery, from: None, to: None, error: None, }, ) .await; } }