mini_apm_admin/api/
health.rs1use axum::{Json, extract::State, http::StatusCode};
2use serde::Serialize;
3use std::time::Instant;
4
5use mini_apm::{DbPool, db};
6
7static START_TIME: std::sync::OnceLock<Instant> = std::sync::OnceLock::new();
8
9pub fn init_start_time() {
10 START_TIME.get_or_init(Instant::now);
11}
12
13#[derive(Serialize)]
14pub struct HealthResponse {
15 pub status: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub error: Option<String>,
18 pub db_size_mb: f64,
19 pub uptime_seconds: u64,
20 pub db_ok: bool,
21}
22
23pub async fn health_handler(State(pool): State<DbPool>) -> (StatusCode, Json<HealthResponse>) {
24 let uptime_seconds = START_TIME.get().map(|t| t.elapsed().as_secs()).unwrap_or(0);
25
26 let db_ok = match pool.get() {
28 Ok(conn) => conn.query_row("SELECT 1", [], |_| Ok(())).is_ok(),
29 Err(_) => false,
30 };
31
32 if db_ok {
33 let db_size_mb = db::get_db_size(&pool).unwrap_or(0.0);
34 (
35 StatusCode::OK,
36 Json(HealthResponse {
37 status: "ok".to_string(),
38 error: None,
39 db_size_mb,
40 uptime_seconds,
41 db_ok: true,
42 }),
43 )
44 } else {
45 tracing::error!("Health check failed: database unreachable");
46 (
47 StatusCode::SERVICE_UNAVAILABLE,
48 Json(HealthResponse {
49 status: "unhealthy".to_string(),
50 error: Some("Database unreachable".to_string()),
51 db_size_mb: 0.0,
52 uptime_seconds,
53 db_ok: false,
54 }),
55 )
56 }
57}