use crate::error::Result;
use crate::types::{HealthStatus, ServiceStatus};
use reqwest::Client;
use std::time::{Duration, Instant};
use tracing::debug;
const HEALTH_CHECK_URL: &str = "https://aur.archlinux.org/rpc/v5/info";
const DEFAULT_HEALTH_CHECK_TIMEOUT: Duration = Duration::from_secs(5);
const DEGRADED_LATENCY_THRESHOLD: Duration = Duration::from_secs(2);
pub async fn check_health(client: &Client, timeout: Option<Duration>) -> Result<HealthStatus> {
let start = Instant::now();
let checked_at = start;
let timeout_duration = timeout.unwrap_or(DEFAULT_HEALTH_CHECK_TIMEOUT);
let result = client
.get(HEALTH_CHECK_URL)
.timeout(timeout_duration)
.send()
.await;
let latency = start.elapsed();
match result {
Ok(response) => {
if !response.status().is_success() {
debug!(
status = %response.status(),
latency_ms = latency.as_millis(),
"health check returned non-success status"
);
return Ok(HealthStatus {
aur_api: ServiceStatus::Unreachable,
latency: Some(latency),
checked_at,
});
}
match response.json::<serde_json::Value>().await {
Ok(json) => {
let is_valid = json.get("version").is_some() && json.get("type").is_some();
if !is_valid {
debug!(
latency_ms = latency.as_millis(),
"health check response missing expected fields"
);
return Ok(HealthStatus {
aur_api: ServiceStatus::Degraded,
latency: Some(latency),
checked_at,
});
}
let status = if latency > DEGRADED_LATENCY_THRESHOLD {
ServiceStatus::Degraded
} else {
ServiceStatus::Healthy
};
debug!(
latency_ms = latency.as_millis(),
?status,
"health check completed"
);
Ok(HealthStatus {
aur_api: status,
latency: Some(latency),
checked_at,
})
}
Err(e) => {
debug!(
error = %e,
latency_ms = latency.as_millis(),
"health check failed to parse response"
);
Ok(HealthStatus {
aur_api: ServiceStatus::Degraded,
latency: Some(latency),
checked_at,
})
}
}
}
Err(e) => {
let status = if e.is_timeout() {
ServiceStatus::Timeout
} else {
ServiceStatus::Unreachable
};
debug!(
error = %e,
?status,
latency_ms = latency.as_millis(),
"health check failed"
);
Ok(HealthStatus {
aur_api: status,
latency: Some(latency),
checked_at,
})
}
}
}