//! backup 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, backup_status_detail, backup_status_priority}; impl Alerter { #[instrument(skip_all)] pub async fn send_backup_stale_alert( &self, target: &str, label: &str, database: &str, status: &str, age_hours: Option, ) { let alert_key = format!("backup:{target}:{database}"); let detail = backup_status_detail(status, age_hours); let subject = format!("[PoM] {label}: {database} backup {status}"); let body = format!( "Target: {label} ({target})\n\ Database: {database}\n\ Status: {status}\n\ Detail: {detail}\n\ Instance: {}\n\ Time: {}\n\n\ - PoM", self.instance_name, chrono::Utc::now().to_rfc3339(), ); let priority = backup_status_priority(status); self.fire_failure( &subject, &body, priority, "pom-backup", Some(&format!("{target}:{database}")), AlertMeta { key: &alert_key, category: AlertCategory::BackupStale, from: None, to: Some(status), error: None, }, ) .await; } #[instrument(skip_all)] pub async fn send_backup_recovery(&self, target: &str, label: &str, database: &str) { let alert_key = format!("backup:{target}:{database}"); let subject = format!("[PoM] {label}: {database} backup recovered"); let body = format!( "Target: {label} ({target})\n\ Database: {database}\n\ Backup is now current.\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::BackupRecovery, from: None, to: Some("ok"), error: None, }, ) .await; } }