use std::time::{Duration, Instant};
pub fn idle_after() -> Duration {
let secs = std::env::var("UNIFIER_IDLE_FLUSH_SECS")
.ok()
.and_then(|s| s.parse::<u64>().ok())
.unwrap_or(5);
Duration::from_secs(secs)
}
pub fn idle_stop_after() -> Duration {
let secs = std::env::var("UNIFIER_IDLE_STOP_SECS")
.ok()
.and_then(|s| s.parse::<u64>().ok())
.unwrap_or(600);
Duration::from_secs(secs)
}
pub fn max_load() -> f64 {
std::env::var("UNIFIER_IDLE_MAX_LOAD")
.ok()
.and_then(|s| s.parse::<f64>().ok())
.unwrap_or(0.2)
}
pub fn loadavg_1min() -> Option<f64> {
let text = std::fs::read_to_string("/proc/loadavg").ok()?;
text.split_whitespace().next()?.parse().ok()
}
pub fn system_is_idle(max: f64) -> bool {
match loadavg_1min() {
Some(load) => load <= max,
None => true,
}
}
pub fn should_idle_flush(
last_activity: Instant,
now: Instant,
idle_after: Duration,
load_ok: bool,
dirty: bool,
tick_active: bool,
) -> bool {
if idle_after.is_zero() || !dirty || tick_active || !load_ok {
return false;
}
now.duration_since(last_activity) >= idle_after
}
pub fn should_idle_stop(
last_activity: Instant,
now: Instant,
idle_stop_after: Duration,
tick_active: bool,
event_subscribers: usize,
) -> bool {
if idle_stop_after.is_zero() || tick_active || event_subscribers > 0 {
return false;
}
now.duration_since(last_activity) >= idle_stop_after
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn waits_for_idle_window() {
let t0 = Instant::now();
let t1 = t0 + Duration::from_secs(2);
assert!(!should_idle_flush(
t0,
t1,
Duration::from_secs(5),
true,
true,
false
));
let t2 = t0 + Duration::from_secs(5);
assert!(should_idle_flush(
t0,
t2,
Duration::from_secs(5),
true,
true,
false
));
}
#[test]
fn parse_loadavg_when_present() {
if let Some(load) = loadavg_1min() {
assert!(load >= 0.0);
}
}
#[test]
fn skips_when_system_busy_or_tick_active_or_clean() {
let t0 = Instant::now();
let now = t0 + Duration::from_secs(10);
let idle = Duration::from_secs(5);
assert!(!should_idle_flush(t0, now, idle, false, true, false));
assert!(!should_idle_flush(t0, now, idle, true, true, true));
assert!(!should_idle_flush(t0, now, idle, true, false, false));
assert!(!should_idle_flush(
t0,
now,
Duration::ZERO,
true,
true,
false
));
}
#[test]
fn idle_stop_requires_quiet_and_no_subscribers() {
let t0 = Instant::now();
let now = t0 + Duration::from_secs(600);
assert!(should_idle_stop(t0, now, Duration::from_secs(600), false, 0));
assert!(!should_idle_stop(t0, now, Duration::from_secs(600), true, 0));
assert!(!should_idle_stop(t0, now, Duration::from_secs(600), false, 1));
assert!(!should_idle_stop(
t0,
now,
Duration::ZERO,
false,
0
));
assert!(!should_idle_stop(
t0,
t0 + Duration::from_secs(10),
Duration::from_secs(600),
false,
0
));
}
}