micromegas/servers/
grpc_health_service.rs

1use http::Request;
2use std::future::Future;
3use std::pin::Pin;
4use tonic::Status;
5use tower::Service;
6
7/// A `tower::Service` that short circuits the other services when the caller is asking for a health check
8#[derive(Clone)]
9pub struct GrpcHealthService<S> {
10    service: S,
11}
12
13impl<S> GrpcHealthService<S> {
14    pub const fn new(service: S) -> Self {
15        Self { service }
16    }
17}
18
19impl<S, Body> Service<http::Request<Body>> for GrpcHealthService<S>
20where
21    Body: Send + 'static + Default,
22    S: Service<http::Request<Body>, Response = http::Response<Body>> + Clone + Send + 'static,
23    S::Error: Into<Box<dyn std::error::Error + Send + Sync>> + std::fmt::Debug,
24    S::Future: Send,
25{
26    type Response = http::Response<Body>;
27    type Error = S::Error;
28    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
29
30    fn poll_ready(
31        &mut self,
32        cx: &mut std::task::Context<'_>,
33    ) -> std::task::Poll<Result<(), Self::Error>> {
34        self.service.poll_ready(cx).map(|_| Ok(()))
35    }
36
37    fn call(&mut self, req: Request<Body>) -> Self::Future {
38        let mut service = self.service.clone();
39        Box::pin(async move {
40            if req.uri().path().ends_with("/health") {
41                let status = Status::ok("health is ok");
42                let response = status.into_http().map(|_: Body| Body::default());
43                return Ok(response);
44            }
45            service.call(req).await
46        })
47    }
48}