diff --git a/keycast/src/main.rs b/keycast/src/main.rs index d3fe1bd8..b09f0680 100644 --- a/keycast/src/main.rs +++ b/keycast/src/main.rs @@ -58,6 +58,9 @@ struct ReadinessState { shutting_down: Arc, } +/// Maps probe state to HTTP status. Shutdown is checked before DB readiness so +/// during graceful shutdown we skip the DB query in [`readyz`] yet still return +/// 503 with body `"Shutting down"` (not `"Database unavailable"`). fn readiness_response(is_shutting_down: bool, database_ready: bool) -> (StatusCode, &'static str) { if is_shutting_down { (StatusCode::SERVICE_UNAVAILABLE, "Shutting down") @@ -86,6 +89,10 @@ async fn livez(state: Arc) -> impl IntoResponse { } } +/// Startup probe: always 200 when reachable. Safe because the listener binds only +/// after `Database::new().await` in startup succeeds; this handler does not +/// re-check the DB. Schema must already be migrated for the revision (e.g. `--migrate` +/// / deploy job—migrations are not run inside `Database::new`). async fn startupz() -> impl IntoResponse { (StatusCode::OK, "OK") } @@ -93,6 +100,8 @@ async fn startupz() -> impl IntoResponse { async fn readyz(state: Arc) -> impl IntoResponse { let is_shutting_down = state.shutting_down.load(Ordering::Relaxed); let database_ready = if is_shutting_down { + // Intentionally skip DB work while shutting down; [`readiness_response`] + // still reports 503 `"Shutting down"` via the shutdown branch first. false } else { // Bound the DB check so a stalled connection or exhausted pool fails @@ -832,6 +841,8 @@ async fn async_main(worker_threads: usize) -> Result<(), Box