micro_kit/
healthcheck.rs

1use std::ops::BitAnd;
2use std::collections::HashMap;
3
4use ::iron::prelude::*;
5use ::iron::status;
6
7use ::serde::{Serialize, Serializer};
8use ::json;
9
10#[derive(Debug, Clone)]
11pub enum HealthCheckStatus {
12    Healthy,
13    Unhealthy,
14}
15
16impl PartialEq for HealthCheckStatus {
17    fn eq(&self, other: &HealthCheckStatus) -> bool {
18        match (self, other) {
19            (&HealthCheckStatus::Healthy, &HealthCheckStatus::Healthy) => true,
20            (&HealthCheckStatus::Unhealthy, &HealthCheckStatus::Unhealthy) => true,
21            _ => false,
22        }
23    }
24}
25
26impl Into<status::Status> for HealthCheckStatus {
27    fn into(self) -> status::Status {
28        match self {
29            HealthCheckStatus::Healthy => status::Ok,
30            HealthCheckStatus::Unhealthy => status::InternalServerError,
31        }
32    }
33}
34
35impl Serialize for HealthCheckStatus {
36    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
37        where S: Serializer
38    {
39        match *self {
40            HealthCheckStatus::Healthy => serializer.serialize_str("Ok"),
41            HealthCheckStatus::Unhealthy => serializer.serialize_str("Failed"),
42        }
43    }
44}
45
46impl BitAnd for HealthCheckStatus {
47    type Output = HealthCheckStatus;
48
49    fn bitand(self, other: HealthCheckStatus) -> HealthCheckStatus {
50        match (self, other) {
51            (HealthCheckStatus::Healthy, HealthCheckStatus::Healthy) => HealthCheckStatus::Healthy,
52            _ => HealthCheckStatus::Unhealthy,
53        }
54    }
55}
56
57pub trait HealthCheck: Send {
58    fn name(&self) -> String;
59
60    fn check_health(&mut self) -> HealthCheckStatus;
61}
62
63#[derive(Default)]
64pub struct HealthCheckService {
65    checks: Vec<Box<HealthCheck + 'static>>,
66}
67
68impl HealthCheckService {
69
70    pub fn register_check<H: HealthCheck + 'static>(&mut self, check: H) {
71        self.checks.push(Box::new(check));
72    }
73
74    pub fn check_service_health(&mut self, _: &mut Request) -> IronResult<Response> {
75        let (global, health) = self.execute();
76
77        let payload = json::to_string(&health).unwrap();
78        let status: status::Status = global.into();
79
80        Ok(Response::with((status, payload)))
81    }
82
83    pub fn execute(&mut self) -> (HealthCheckStatus, HashMap<String, HealthCheckStatus>) {
84        let mut map = HashMap::new();
85
86        for check in &mut self.checks {
87            let res = check.check_health();
88            map.insert(check.name(), res);
89        }
90
91        let global_health = map.values()
92            .fold(HealthCheckStatus::Healthy, |check, val| check & val.clone());
93
94        (global_health, map)
95    }
96}