use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;
#[derive(Clone, Debug, PartialEq)]
pub enum HealthStatus {
Healthy,
Degraded { reason: String },
Unhealthy { reason: String },
}
impl HealthStatus {
pub fn is_healthy(&self) -> bool {
matches!(self, HealthStatus::Healthy)
}
pub fn is_degraded(&self) -> bool {
matches!(self, HealthStatus::Degraded { .. })
}
pub fn is_unhealthy(&self) -> bool {
matches!(self, HealthStatus::Unhealthy { .. })
}
pub fn reason(&self) -> Option<&str> {
match self {
HealthStatus::Healthy => None,
HealthStatus::Degraded { reason } => Some(reason),
HealthStatus::Unhealthy { reason } => Some(reason),
}
}
}
pub struct HealthChecker {
checks: Arc<RwLock<HashMap<String, HealthStatus>>>,
interval: Duration,
}
impl HealthChecker {
pub fn new(interval: Duration) -> Self {
Self {
checks: Arc::new(RwLock::new(HashMap::new())),
interval,
}
}
pub async fn register(&self, name: String, initial_status: HealthStatus) {
let mut checks = self.checks.write().await;
checks.insert(name, initial_status);
}
pub async fn update(&self, name: &str, status: HealthStatus) {
let mut checks = self.checks.write().await;
checks.insert(name.to_string(), status);
}
pub async fn check_one(&self, name: &str) -> Option<HealthStatus> {
let checks = self.checks.read().await;
checks.get(name).cloned()
}
pub async fn check_all(&self) -> HashMap<String, HealthStatus> {
let checks = self.checks.read().await;
checks.clone()
}
pub fn interval(&self) -> Duration {
self.interval
}
pub async fn unregister(&self, name: &str) {
let mut checks = self.checks.write().await;
checks.remove(name);
}
}