use crate::engine::api::state::ApiState;
use axum::{Json, extract::State};
use serde::Serialize;
use std::time::Instant;
#[derive(Serialize)]
pub struct Components {
cache: ComponentStatus,
db: ComponentStatus,
}
#[derive(Serialize)]
pub struct ComponentStatus {
status: String,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<String>,
}
#[derive(Serialize)]
pub struct HealthResponse {
status: String,
components: Components,
}
impl ComponentStatus {
fn up() -> Self {
Self {
status: "up".to_string(),
error: None,
}
}
fn down(e: impl ToString) -> Self {
Self {
status: "down".to_string(),
error: Some(e.to_string()),
}
}
}
pub async fn health_check(State(state): State<ApiState>) -> Json<HealthResponse> {
let started = Instant::now();
let cache_status = match state.state.cache_service.ping().await {
Ok(_) => ComponentStatus::up(),
Err(e) => ComponentStatus::down(e),
};
let db_status = match state.state.db.ping().await {
Ok(_) => ComponentStatus::up(),
Err(e) => ComponentStatus::down(e),
};
let global_status = if cache_status.status == "up" && db_status.status == "up" {
"up"
} else {
"degraded"
};
crate::common::metrics::set_component_health("cache", cache_status.status == "up");
crate::common::metrics::set_component_health("db", db_status.status == "up");
crate::common::metrics::inc_throughput(
"control_plane",
"health",
"health_check",
global_status,
1,
);
crate::common::metrics::observe_latency(
"control_plane",
"health",
"health_check",
global_status,
started.elapsed().as_secs_f64(),
);
Json(HealthResponse {
status: global_status.to_string(),
components: Components {
cache: cache_status,
db: db_status,
},
})
}