aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/health.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-31 12:22:24 +0100
committertv <tv@krebsco.de>2026-10-31 12:22:24 +0100
commit2c4a60b91bf60b0d87a862641a6016b1f7a251ec (patch)
tree8f57f7e38dcd60468bf3a3be755e5b659925fd9f /src/api/health.rs
parente360bc6da05f1c83c08946763c93e5b16db4e19d (diff)
api: add clocks to /health
Diffstat (limited to 'src/api/health.rs')
-rw-r--r--src/api/health.rs21
1 files changed, 19 insertions, 2 deletions
diff --git a/src/api/health.rs b/src/api/health.rs
index b1e4523..3bd374e 100644
--- a/src/api/health.rs
+++ b/src/api/health.rs
@@ -1,15 +1,32 @@
//! `GET /health` and `GET /ready`: unauthenticated, for supervisors and load balancers.
-//! They say whether the node is up and whether it serves the store, nothing more.
+//! 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.
+/// 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 {