use crate::application::lifecycle::{Lifecycle, LifecycleState};
use crate::axum::Extension;
use crate::axum::http::StatusCode;
use crate::axum::response::IntoResponse;
#[must_use]
pub fn ready_response(lifecycle: &Lifecycle) -> (StatusCode, &'static str) {
let state = lifecycle.state();
if lifecycle.ready() {
return (StatusCode::OK, "ready");
}
let body = match state {
LifecycleState::Starting => "starting",
LifecycleState::Draining => "draining",
LifecycleState::Stopped => "stopped",
LifecycleState::Ready => "unready",
};
(StatusCode::SERVICE_UNAVAILABLE, body)
}
pub(crate) async fn ready(Extension(lifecycle): Extension<Lifecycle>) -> impl IntoResponse {
ready_response(&lifecycle)
}
#[cfg(test)]
mod tests {
use super::ready_response;
use crate::application::lifecycle::Lifecycle;
use crate::axum::http::StatusCode;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
#[test]
fn ready_returns_503_while_starting() {
let lifecycle = Lifecycle::new();
let (status, body) = ready_response(&lifecycle);
assert_eq!(status, StatusCode::SERVICE_UNAVAILABLE);
assert_eq!(body, "starting");
}
#[test]
fn ready_returns_200_when_ready_and_no_checks() {
let lifecycle = Lifecycle::new();
lifecycle.mark_ready();
let (status, body) = ready_response(&lifecycle);
assert_eq!(status, StatusCode::OK);
assert_eq!(body, "ready");
}
#[test]
fn ready_returns_503_when_ready_but_check_fails() {
let flag = Arc::new(AtomicBool::new(false));
let flag_for_check = flag.clone();
let lifecycle =
Lifecycle::new().register_readiness(move || flag_for_check.load(Ordering::SeqCst));
lifecycle.mark_ready();
let (status, body) = ready_response(&lifecycle);
assert_eq!(status, StatusCode::SERVICE_UNAVAILABLE);
assert_eq!(body, "unready");
flag.store(true, Ordering::SeqCst);
let (status, body) = ready_response(&lifecycle);
assert_eq!(status, StatusCode::OK);
assert_eq!(body, "ready");
}
#[test]
fn ready_returns_503_while_draining_even_if_checks_pass() {
let lifecycle = Lifecycle::new();
lifecycle.mark_ready();
lifecycle.begin_drain();
let (status, body) = ready_response(&lifecycle);
assert_eq!(status, StatusCode::SERVICE_UNAVAILABLE);
assert_eq!(body, "draining");
}
#[test]
fn ready_returns_503_when_stopped() {
let lifecycle = Lifecycle::new();
lifecycle.mark_stopped();
let (status, body) = ready_response(&lifecycle);
assert_eq!(status, StatusCode::SERVICE_UNAVAILABLE);
assert_eq!(body, "stopped");
}
}