Skip to main content

syspulse_core/health/
http.rs

1use async_trait::async_trait;
2use std::time::Duration;
3
4use super::HealthChecker;
5use crate::daemon::{HealthCheckSpec, HealthStatus};
6use crate::error::{Result, SyspulseError};
7
8pub struct HttpHealthChecker {
9    spec: HealthCheckSpec,
10    client: reqwest::Client,
11}
12
13impl HttpHealthChecker {
14    pub fn new(spec: HealthCheckSpec) -> Self {
15        let client = reqwest::Client::builder()
16            .timeout(Duration::from_secs(spec.timeout_secs))
17            .build()
18            .unwrap_or_default();
19        Self { spec, client }
20    }
21}
22
23#[async_trait]
24impl HealthChecker for HttpHealthChecker {
25    async fn check(&self) -> Result<HealthStatus> {
26        match self.client.get(&self.spec.target).send().await {
27            Ok(resp) => {
28                if resp.status().is_success() {
29                    Ok(HealthStatus::Healthy)
30                } else {
31                    tracing::debug!(
32                        url = %self.spec.target,
33                        status = %resp.status(),
34                        "HTTP health check returned non-2xx"
35                    );
36                    Ok(HealthStatus::Unhealthy)
37                }
38            }
39            Err(e) => {
40                tracing::debug!(
41                    url = %self.spec.target,
42                    error = %e,
43                    "HTTP health check failed"
44                );
45                if e.is_timeout() {
46                    Err(SyspulseError::Timeout(Duration::from_secs(
47                        self.spec.timeout_secs,
48                    )))
49                } else {
50                    Ok(HealthStatus::Unhealthy)
51                }
52            }
53        }
54    }
55
56    fn spec(&self) -> &HealthCheckSpec {
57        &self.spec
58    }
59}