use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum HealthStatus {
Healthy,
Degraded { reason: String },
Unhealthy { reason: String },
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentHealth {
pub name: String,
pub healthy: bool,
pub last_check: DateTime<Utc>,
pub error: Option<String>,
pub latency_ms: Option<u64>,
pub metadata: serde_json::Value,
}
impl ComponentHealth {
pub fn healthy(name: impl Into<String>, latency_ms: u64) -> Self {
Self {
name: name.into(),
healthy: true,
last_check: Utc::now(),
error: None,
latency_ms: Some(latency_ms),
metadata: serde_json::Value::Null,
}
}
pub fn unhealthy(name: impl Into<String>, error: impl Into<String>) -> Self {
Self {
name: name.into(),
healthy: false,
last_check: Utc::now(),
error: Some(error.into()),
latency_ms: None,
metadata: serde_json::Value::Null,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthReport {
pub overall: HealthStatus,
pub components: HashMap<String, ComponentHealth>,
pub checked_at: DateTime<Utc>,
pub uptime_secs: u64,
pub version: String,
}
impl HealthReport {
pub fn is_ready(&self) -> bool {
Self::required_components().iter().all(|name| {
self.components
.get(*name)
.map(|h| h.healthy)
.unwrap_or(false)
})
}
pub fn required_components() -> &'static [&'static str] {
&["core", "vector", "guard", "branch"]
}
pub fn optional_components() -> &'static [&'static str] {
&["sync", "reflect"]
}
}