use super::funejson::Value; /// New, up, late or down, as healthchecks.io names them. Up through the due /// second itself, late through the last second of the grace time, down /// after. A ping stamped in the future (clock skew between the job and the /// monitor) is simply up: its due time is later still. /// /// # Panics /// Panics when interval_seconds is below 1 or grace_seconds is negative. pub fn heartbeat_status(last_ping_at: Option, now: i64, interval_seconds: i64, grace_seconds: i64) -> HeartbeatStatus { if interval_seconds < 1 { panic!("intervalSeconds must be at least 1, received {}", interval_seconds); } if grace_seconds < 0 { panic!("graceSeconds must not be negative, received {}", grace_seconds); } let last = match last_ping_at { None => return HeartbeatStatus { state: "new".to_string(), due_at: None, down_at: None, overdue_seconds: 0 }, Some(l) => l, }; let due_at = last + interval_seconds; let down_at = due_at + grace_seconds; if now <= due_at { return HeartbeatStatus { state: "up".to_string(), due_at: Some(due_at), down_at: Some(down_at), overdue_seconds: 0 }; } let state = if now <= down_at { "late" } else { "down" }; HeartbeatStatus { state: state.to_string(), due_at: Some(due_at), down_at: Some(down_at), overdue_seconds: now - due_at } } pub fn heartbeat_status_to_value(s: &HeartbeatStatus) -> Value { let opt = |o: Option| match o { Some(i) => Value::Int(i), None => Value::Null, }; Value::obj(vec![ ("state", Value::str(&s.state)), ("dueAt", opt(s.due_at)), ("downAt", opt(s.down_at)), ("overdueSeconds", Value::Int(s.overdue_seconds)), ]) } fn whole(name: &str, v: &Value) -> i64 { match v { Value::Int(i) => *i, Value::Float(f) => panic!("{} must be whole seconds, received {}", name, f), _ => panic!("{} must be whole seconds", name), } } pub fn fune_vector(args: &[Value]) -> Value { let last = if args[0].is_null() { None } else { Some(whole("lastPingAt", &args[0])) }; let s = heartbeat_status( last, whole("now", &args[1]), whole("intervalSeconds", &args[2]), whole("graceSeconds", &args[3]), ); heartbeat_status_to_value(&s) }