iota_rest_api/
health.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::time::{Duration, SystemTime};
6
7use axum::{
8    extract::{Query, State},
9    http::StatusCode,
10    response::IntoResponse,
11};
12use iota_types::storage::ReadStore;
13use tap::Pipe;
14
15use crate::{
16    RestService, Result,
17    openapi::{ApiEndpoint, OperationBuilder, ResponseBuilder, RouteHandler},
18    reader::StateReader,
19};
20
21pub struct HealthCheck;
22
23impl ApiEndpoint<RestService> for HealthCheck {
24    fn method(&self) -> axum::http::Method {
25        axum::http::Method::GET
26    }
27
28    fn path(&self) -> &'static str {
29        "/health"
30    }
31
32    fn operation(
33        &self,
34        generator: &mut schemars::gen::SchemaGenerator,
35    ) -> openapiv3::v3_1::Operation {
36        OperationBuilder::new()
37            .tag("General")
38            .operation_id("HealthCheck")
39            .query_parameters::<Threshold>(generator)
40            .response(200, ResponseBuilder::new().text_content().build())
41            .build()
42    }
43
44    fn handler(&self) -> crate::openapi::RouteHandler<RestService> {
45        RouteHandler::new(self.method(), health)
46    }
47}
48
49#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
50pub struct Threshold {
51    pub threshold_seconds: Option<u32>,
52}
53
54async fn health(
55    Query(Threshold { threshold_seconds }): Query<Threshold>,
56    State(state): State<StateReader>,
57) -> Result<impl IntoResponse> {
58    let summary = state.inner().get_latest_checkpoint()?;
59
60    // If we have a provided threshold, check that it's close to the current time
61    if let Some(threshold_seconds) = threshold_seconds {
62        let latest_chain_time = summary.timestamp();
63
64        let threshold = SystemTime::now() - Duration::from_secs(threshold_seconds as u64);
65
66        if latest_chain_time < threshold {
67            return Err(anyhow::anyhow!(
68                "The latest checkpoint timestamp is less than the provided threshold"
69            )
70            .into());
71        }
72    }
73
74    StatusCode::OK.pipe(Ok)
75}