Files
healthpot/src/health/mod.rs
2021-01-31 01:42:39 +01:00

77 lines
2.0 KiB
Rust

use chrono::{DateTime, Utc};
use futures::lock::Mutex;
use log::info;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub type ServiceId = String;
#[derive(Debug)]
pub enum HealthStatus {
/// The service is up and running
Up,
/// The service gave an error when performing the health check
Errored,
/// The service did not respond to the health check
Down,
}
#[derive(Serialize, Deserialize)]
pub struct ServiceConfig {
pub url: String,
pub mode: HttpHealthCheckMode,
}
#[derive(Serialize, Deserialize)]
pub enum HttpHealthCheckMode {
/// Expect the server to return a 200 status code. The body is ignored.
Check200,
}
pub struct HealthState {
pub last_update: Mutex<Option<DateTime<Utc>>>,
pub health: HashMap<ServiceId, Mutex<Option<HealthStatus>>>,
pub config: HealthConfig,
}
#[derive(Serialize, Deserialize)]
pub struct HealthConfig {
/// The time between updates (in seconds)
pub update_period: u64,
/// The list of services
pub services: HashMap<ServiceId, ServiceConfig>,
}
impl HealthState {
pub fn new(config: HealthConfig) -> HealthState {
HealthState {
last_update: Mutex::new(None),
health: config
.services
.iter()
.map(|(id, _config)| (id.clone(), Mutex::new(None)))
.collect(),
config,
}
}
pub async fn update(&self) {
*self.last_update.lock().await = Some(Utc::now());
for (id, status) in &self.health {
let url = &self.config.services[id].url;
info!("service [{}] querying {}", id, url);
let new_status = match reqwest::get(url).await {
Err(_) => HealthStatus::Down,
Ok(response) if response.status().is_success() => HealthStatus::Up,
Ok(_response) => HealthStatus::Errored,
};
info!("service [{}] new status {:?}", id, new_status);
*status.lock().await = Some(new_status);
}
}
}