1#![cfg(feature = "server")]
12
13use axum::http::StatusCode;
14use axum::Json;
15use serde_json::{json, Value};
16use std::time::Duration;
17
18const PROBE_TIMEOUT: Duration = Duration::from_secs(2);
23
24pub async fn healthz() -> Json<Value> {
29 Json(json!({ "status": "ok" }))
30}
31
32pub async fn readyz() -> (StatusCode, Json<Value>) {
46 use crate::db::pool::DB_POOL;
47
48 let s = DB_POOL.status();
50 let pool_info = json!({
51 "size": s.size,
52 "available": s.available,
53 "max_size": s.max_size,
54 "waiting": s.waiting,
55 });
56
57 match tokio::time::timeout(PROBE_TIMEOUT, DB_POOL.get()).await {
59 Ok(Ok(conn)) => match conn.simple_query("SELECT 1").await {
60 Ok(_) => (
61 StatusCode::OK,
62 Json(json!({ "status": "ready", "db": "ok", "pool": pool_info })),
63 ),
64 Err(e) => {
65 tracing::warn!(error = ?e, "readiness database probe query failed");
66 (
67 StatusCode::SERVICE_UNAVAILABLE,
68 Json(json!({
69 "status": "unready",
70 "db": "error",
71 "pool": pool_info
72 })),
73 )
74 }
75 },
76 Ok(Err(e)) => {
77 tracing::warn!(error = ?e, "readiness database connection failed");
78 (
79 StatusCode::SERVICE_UNAVAILABLE,
80 Json(json!({
81 "status": "unready",
82 "db": "down",
83 "pool": pool_info
84 })),
85 )
86 }
87 Err(_) => {
88 tracing::warn!("readiness database probe timed out");
89 (
90 StatusCode::SERVICE_UNAVAILABLE,
91 Json(json!({
92 "status": "unready",
93 "db": "timeout",
94 "pool": pool_info
95 })),
96 )
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn healthz_returns_ok_status() {
107 let expected = json!({ "status": "ok" });
110 assert_eq!(expected["status"], "ok");
111 }
112
113 #[test]
114 fn readyz_pool_info_has_all_fields() {
115 let size = 5usize;
119 let available = 3usize;
120 let max_size = 20usize;
121 let waiting = 0usize;
122 let pool_info = json!({
123 "size": size,
124 "available": available,
125 "max_size": max_size,
126 "waiting": waiting,
127 });
128 assert_eq!(pool_info["max_size"], 20);
129 assert_eq!(pool_info["size"], 5);
130 assert_eq!(pool_info["available"], 3);
131 assert_eq!(pool_info["waiting"], 0);
132 }
133
134 #[test]
135 fn probe_timeout_is_two_seconds() {
136 assert_eq!(PROBE_TIMEOUT, Duration::from_secs(2));
137 }
138}