cat_gateway/service/utilities/middleware/
db_check.rs

1//! Middleware to verify that there is connection the databases.
2
3use poem::{http::StatusCode, Endpoint, Middleware, Request, Result};
4use tracing::error;
5
6use crate::service::utilities::health::{event_db_is_live, index_db_is_live};
7
8/// Middleware type that returns a response with 503 status code
9/// if any DB stops responding before returning the wrapped endpoint.
10pub(crate) struct DatabaseConnectionCheck;
11
12impl<E: Endpoint> Middleware<E> for DatabaseConnectionCheck {
13    type Output = DatabaseConnectionImpl<E>;
14
15    fn transform(&self, ep: E) -> Self::Output {
16        DatabaseConnectionImpl { ep }
17    }
18}
19
20/// The new endpoint type generated by the `DatabaseConnectionCheck`.
21pub(crate) struct DatabaseConnectionImpl<E> {
22    /// Endpoint wrapped by the middleware.
23    ep: E,
24}
25
26impl<E: Endpoint> Endpoint for DatabaseConnectionImpl<E> {
27    type Output = E::Output;
28
29    async fn call(&self, req: Request) -> Result<Self::Output> {
30        let req_path = req.uri().path();
31
32        // TODO: find a better way to filter URI paths
33        let is_health_endpoint = req_path.starts_with("/api/v1/health/");
34
35        if !is_health_endpoint {
36            if !event_db_is_live() {
37                error!(endpoint_path = %req_path, "Event DB is not live");
38                return Err(StatusCode::SERVICE_UNAVAILABLE.into());
39            }
40            if !index_db_is_live() {
41                error!(endpoint_path = %req_path, "Index DB is not live");
42                return Err(StatusCode::SERVICE_UNAVAILABLE.into());
43            }
44        }
45        self.ep.call(req).await
46    }
47}