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        let is_metrics_endpoint = req_path == "/metrics";
35
36        if !(is_health_endpoint || is_metrics_endpoint) {
37            if !event_db_is_live() {
38                error!(endpoint_path = %req_path, "Event DB is not live");
39                return Err(StatusCode::SERVICE_UNAVAILABLE.into());
40            }
41            if !index_db_is_live() {
42                error!(endpoint_path = %req_path, "Index DB is not live");
43                return Err(StatusCode::SERVICE_UNAVAILABLE.into());
44            }
45        }
46        self.ep.call(req).await
47    }
48}