systemprompt_api/services/health/
checker.rs1use anyhow::{anyhow, Result};
2use std::time::Duration;
3use tokio::time::sleep;
4use tracing::{info, warn};
5
6#[derive(Debug)]
7pub struct HealthChecker {
8 url: String,
9 max_retries: u32,
10 retry_delay: Duration,
11}
12
13impl HealthChecker {
14 pub const fn new(url: String) -> Self {
15 Self {
16 url,
17 max_retries: 20,
18 retry_delay: Duration::from_secs(3),
19 }
20 }
21
22 pub const fn with_max_retries(mut self, max_retries: u32) -> Self {
23 self.max_retries = max_retries;
24 self
25 }
26
27 pub const fn with_retry_delay(mut self, retry_delay: Duration) -> Self {
28 self.retry_delay = retry_delay;
29 self
30 }
31
32 pub async fn check(&self) -> Result<()> {
33 info!("Performing health checks");
34
35 let client = reqwest::Client::builder()
36 .timeout(Duration::from_secs(5))
37 .build()?;
38
39 for attempt in 0..self.max_retries {
40 sleep(self.retry_delay).await;
41
42 match client.get(&self.url).send().await {
43 Ok(response) if response.status().is_success() => {
44 info!("API health check passed");
45 return Ok(());
46 },
47 Ok(response) => {
48 let remaining = self.max_retries - attempt - 1;
49 warn!(
50 attempt = attempt + 1,
51 max_retries = self.max_retries,
52 status = %response.status(),
53 retry_delay_secs = self.retry_delay.as_secs(),
54 retries_remaining = remaining,
55 "Health check failed, retrying"
56 );
57 },
58 Err(e) => {
59 let remaining = self.max_retries - attempt - 1;
60 warn!(
61 attempt = attempt + 1,
62 max_retries = self.max_retries,
63 error = %e,
64 retry_delay_secs = self.retry_delay.as_secs(),
65 retries_remaining = remaining,
66 "Health check failed, retrying"
67 );
68 },
69 }
70 }
71
72 Err(anyhow!(
73 "Health check failed after {} attempts ({} seconds)",
74 self.max_retries,
75 self.max_retries * self.retry_delay.as_secs() as u32
76 ))
77 }
78}