summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-26 20:34:51 +0100
committertv <tv@krebsco.de>2026-10-26 20:34:51 +0100
commit75c1d950314fb7fa8b88bae957e6083bb1091001 (patch)
treea81e8fa40e44f0378d2af43787a662c0bc2c2933 /src
parentc7d6d626f7d9cad8c99741dab48559610c32ba7b (diff)
add unauthenticated /health and /ready endpoints
Diffstat (limited to 'src')
-rw-r--r--src/api/health.rs20
-rw-r--r--src/api/mod.rs6
2 files changed, 25 insertions, 1 deletions
diff --git a/src/api/health.rs b/src/api/health.rs
new file mode 100644
index 0000000..b1e4523
--- /dev/null
+++ b/src/api/health.rs
@@ -0,0 +1,20 @@
+//! `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.
+
+use axum::{extract::State, http::StatusCode};
+
+use crate::state::AppState;
+
+/// The HTTP API is up.
+pub(crate) async fn health() -> &'static str {
+ "ok\n"
+}
+
+/// 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")
+ }
+}
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 296fa5e..bf7b06b 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -3,6 +3,7 @@
pub(crate) mod auth;
mod debug;
mod document;
+mod health;
mod log;
mod peers;
mod stats;
@@ -31,7 +32,8 @@ use crate::document::meta;
use crate::document::store::StoreError;
use crate::state::AppState;
-/// Builds the complete HTTP router. Everything except Swagger is authenticated.
+/// Builds the complete HTTP router. Everything except Swagger, `/health` and `/ready` is
+/// authenticated.
pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) -> Router {
let mut api: Router<AppState> = Router::new()
.route("/store", get(store::get_store_root))
@@ -64,6 +66,8 @@ pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) ->
api.layer(middleware::from_fn_with_state(auth_state, basic_auth))
.merge(SwaggerUi::new("/swagger-ui").url("/openapi.json", ApiDoc::openapi()))
+ .route("/health", get(health::health))
+ .route("/ready", get(health::ready))
// Outermost, so authentication failures get the error body too.
.layer(middleware::from_fn(json_errors))
.with_state(state)