aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/health.rs
blob: 3bd374e07ac1b80aebb2465ba7b57f55a02a7acb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//! `GET /health` and `GET /ready`: unauthenticated, for supervisors and load balancers.
//! They say whether the node is up and whether it serves the store, and `/health` on a
//! node whether its clock is off, nothing more.

use std::time::Duration;

use axum::{extract::State, http::StatusCode};

use crate::state::AppState;

/// The HTTP API is up (a relay's).
pub(crate) async fn health() -> &'static str {
    "ok\n"
}

/// The HTTP API is up (a node's); a second line while its clock is off from its peers'
/// (`swarm::skew`), which doesn't make it less up.
pub(crate) async fn node_health(State(state): State<AppState>) -> String {
    let skew = crate::swarm::skew::measure(&state).await;
    match skew.offset_ms {
        Some(offset) if skew.off => format!(
            "ok\nclock off: {} {} most of its peers'\n",
            crate::units::format_duration(Duration::from_millis(offset.unsigned_abs())),
            if offset < 0 { "behind" } else { "ahead of" }
        ),
        _ => "ok\n".to_owned(),
    }
}

/// The node serves reads and writes: ready, not joining or rejoining.
pub(crate) async fn ready(State(state): State<AppState>) -> (StatusCode, &'static str) {
    if state.is_ready().await {
        (StatusCode::OK, "ready\n")
    } else {
        (StatusCode::SERVICE_UNAVAILABLE, "not ready\n")
    }
}