//! Shared health-probe handlers for the standalone and cluster routers. //! //! The standalone router ([`crate::router`]) and the cluster router //! ([`crate::cluster`]) both expose the same Kubernetes-style probe endpoints //! `GET /health/startup` and `GET /health/live`. Their handlers and the JSON //! body they return were previously byte-identical copies in each module; any //! drift between the two (e.g. a renamed field on one side) would silently //! change one mode's probe contract. This module is the single source of truth //! so the two routers cannot diverge, mirroring the [`crate::dto`] anti-drift //! pattern for the data surface. use axum::Json; /// Shared probe body: `{"ok": true, "service": "tidaldb"}`. /// /// Both `/health/startup` and `/health/live` return this fixed body — they are /// unconditional 200s (the process is up and there are no migrations to gate /// readiness on). The richer mode-specific readiness check (`GET /health`) /// stays in each router because it inspects mode-specific state. fn probe_body() -> serde_json::Value { serde_json::json!({ "ok": true, "service": "tidaldb" }) } /// Startup probe: always 200 (no migrations to check). pub async fn health_startup() -> Json { Json(probe_body()) } /// Liveness probe: always 200 (process is alive). pub async fn health_live() -> Json { Json(probe_body()) } #[cfg(test)] mod tests { use super::*; /// Both probes return the same fixed body, so the standalone and cluster /// routers cannot advertise a different probe contract. #[tokio::test] async fn probes_return_shared_body() { let expected = serde_json::json!({ "ok": true, "service": "tidaldb" }); assert_eq!(health_startup().await.0, expected); assert_eq!(health_live().await.0, expected); assert_eq!(probe_body(), expected); } }