Skip to main content

foxtive_worker/
http.rs

1use crate::health::{HealthCheck, HealthStatus};
2use std::sync::Arc;
3
4/// A wrapper to expose worker pool health via an HTTP endpoint.
5///
6/// This struct implements traits for common web frameworks to make
7/// integrating health checks into your application straightforward.
8pub struct HealthEndpoint {
9    pub(crate) check: Arc<dyn HealthCheck>,
10}
11
12impl HealthEndpoint {
13    /// Create a new health endpoint from a health-checkable component.
14    pub fn new(check: impl HealthCheck + 'static) -> Self {
15        Self {
16            check: Arc::new(check),
17        }
18    }
19
20    /// Get the current health status as a JSON-serializable string.
21    pub fn get_status_json(&self) -> String {
22        let status = self.check.check_health();
23        let message = self.check.status_message();
24
25        let status_str = match status {
26            HealthStatus::Healthy => "healthy",
27            HealthStatus::Degraded { .. } => "degraded",
28            HealthStatus::Unhealthy { .. } => "unhealthy",
29        };
30
31        format!(
32            "{{\"status\":\"{}\",\"message\":\"{}\"}}",
33            status_str,
34            message.replace('"', "\\\"")
35        )
36    }
37
38    /// Get the HTTP status code corresponding to the current health.
39    pub fn get_http_status_code(&self) -> u16 {
40        match self.check.check_health() {
41            HealthStatus::Healthy => 200,
42            HealthStatus::Degraded { .. } => 200, // Often degraded is still 200 but with info
43            HealthStatus::Unhealthy { .. } => 503,
44        }
45    }
46}
47
48#[cfg(feature = "http")]
49mod axum_integration {
50    use super::*;
51    use axum::{Json, http::StatusCode, response::IntoResponse};
52    use serde::Serialize;
53
54    #[derive(Serialize)]
55    struct HealthResponse {
56        status: String,
57        message: String,
58    }
59
60    impl IntoResponse for HealthEndpoint {
61        fn into_response(self) -> axum::response::Response {
62            let status = self.check.check_health();
63            let message = self.check.status_message();
64
65            let (code, status_str) = match status {
66                HealthStatus::Healthy => (StatusCode::OK, "healthy"),
67                HealthStatus::Degraded { .. } => (StatusCode::OK, "degraded"),
68                HealthStatus::Unhealthy { .. } => (StatusCode::SERVICE_UNAVAILABLE, "unhealthy"),
69            };
70
71            let body = Json(HealthResponse {
72                status: status_str.to_string(),
73                message,
74            });
75
76            (code, body).into_response()
77        }
78    }
79}