use super::Alert;
use crate::error::Result;
use chrono::{DateTime, Duration, Utc};
use parking_lot::RwLock;
use std::sync::Arc;
pub struct EscalationPolicy {
pub name: String,
pub levels: Vec<EscalationLevel>,
}
pub struct EscalationLevel {
pub delay: Duration,
pub recipients: Vec<String>,
}
pub struct EscalationManager {
policies: Arc<RwLock<HashMap<String, EscalationPolicy>>>,
escalations: Arc<RwLock<HashMap<String, EscalationState>>>,
}
use std::collections::HashMap;
#[derive(Clone)]
#[allow(dead_code)]
struct EscalationState {
alert: Alert,
current_level: usize,
last_escalated_at: DateTime<Utc>,
}
impl EscalationManager {
pub fn new() -> Self {
Self {
policies: Arc::new(RwLock::new(HashMap::new())),
escalations: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn add_policy(&self, policy: EscalationPolicy) {
self.policies.write().insert(policy.name.clone(), policy);
}
pub fn start_escalation(&self, alert: Alert, policy_name: &str) -> Result<()> {
let policies = self.policies.read();
let _policy = policies.get(policy_name).ok_or_else(|| {
crate::error::ObservabilityError::NotFound(format!("Policy {}", policy_name))
})?;
let state = EscalationState {
alert: alert.clone(),
current_level: 0,
last_escalated_at: Utc::now(),
};
self.escalations.write().insert(alert.id.clone(), state);
Ok(())
}
pub async fn check_escalations(&self) -> Result<()> {
let policies = self.policies.read();
let mut escalations = self.escalations.write();
for (_alert_id, state) in escalations.iter_mut() {
let elapsed = Utc::now() - state.last_escalated_at;
for policy in policies.values() {
if state.current_level < policy.levels.len() {
let level = &policy.levels[state.current_level];
if elapsed >= level.delay {
state.current_level += 1;
state.last_escalated_at = Utc::now();
}
}
}
}
Ok(())
}
}
impl Default for EscalationManager {
fn default() -> Self {
Self::new()
}
}