#[derive(Clone, Copy, Debug, Default)]
pub struct SnapshotTriggerConfig {
pub at_heartbeat: Option<u64>,
pub on_pre_exec: bool,
pub on_listener: bool,
pub after_ms: Option<u64>,
}
#[derive(Clone, Copy, Debug)]
pub struct TriggerSignals {
pub heartbeat_count: u64,
pub pre_exec_ready: bool,
pub workload_parked: bool,
pub listener_count: usize,
pub elapsed_ms: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TriggerFire {
pub reason: &'static str,
pub needs_quiesce: bool,
}
impl SnapshotTriggerConfig {
pub fn evaluate(&self, sig: &TriggerSignals) -> Option<TriggerFire> {
if let Some(target) = self.at_heartbeat {
if sig.heartbeat_count >= target {
return Some(TriggerFire {
reason: "heartbeat",
needs_quiesce: true,
});
}
}
if self.on_pre_exec && sig.pre_exec_ready {
return Some(TriggerFire {
reason: "pre-exec",
needs_quiesce: false,
});
}
if self.on_listener && sig.listener_count > 0 {
return Some(TriggerFire {
reason: "listener-ready",
needs_quiesce: true,
});
}
if self.on_listener && sig.listener_count == 0 && sig.workload_parked {
return Some(TriggerFire {
reason: "workload-parked",
needs_quiesce: false,
});
}
if let Some(after_ms) = self.after_ms {
if sig.elapsed_ms >= after_ms {
return Some(TriggerFire {
reason: "wall-clock",
needs_quiesce: false,
});
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sig() -> TriggerSignals {
TriggerSignals {
heartbeat_count: 0,
pre_exec_ready: false,
workload_parked: false,
listener_count: 0,
elapsed_ms: 0,
}
}
#[test]
fn nothing_fires_when_no_signal_is_ready() {
let cfg = SnapshotTriggerConfig {
at_heartbeat: Some(3),
on_pre_exec: true,
on_listener: true,
after_ms: Some(7000),
};
assert_eq!(cfg.evaluate(&sig()), None);
}
#[test]
fn heartbeat_fires_at_or_past_target_and_quiesces() {
let cfg = SnapshotTriggerConfig {
at_heartbeat: Some(3),
..Default::default()
};
assert_eq!(
cfg.evaluate(&TriggerSignals {
heartbeat_count: 2,
..sig()
}),
None,
"below target"
);
let f = cfg
.evaluate(&TriggerSignals {
heartbeat_count: 3,
..sig()
})
.unwrap();
assert_eq!(f.reason, "heartbeat");
assert!(f.needs_quiesce);
}
#[test]
fn priority_order_is_respected() {
let cfg = SnapshotTriggerConfig {
at_heartbeat: Some(1),
on_pre_exec: true,
on_listener: true,
after_ms: Some(0),
};
let all = TriggerSignals {
heartbeat_count: 5,
pre_exec_ready: true,
workload_parked: true,
listener_count: 2,
elapsed_ms: 9999,
};
assert_eq!(cfg.evaluate(&all).unwrap().reason, "heartbeat");
let cfg2 = SnapshotTriggerConfig {
on_pre_exec: true,
on_listener: true,
after_ms: Some(0),
..Default::default()
};
assert_eq!(cfg2.evaluate(&all).unwrap().reason, "pre-exec");
}
#[test]
fn listener_ready_beats_parked_and_wall_clock() {
let cfg = SnapshotTriggerConfig {
on_listener: true,
after_ms: Some(0),
..Default::default()
};
let f = cfg
.evaluate(&TriggerSignals {
listener_count: 1,
workload_parked: true,
elapsed_ms: 9999,
..sig()
})
.unwrap();
assert_eq!(f.reason, "listener-ready");
assert!(f.needs_quiesce);
}
#[test]
fn parked_fires_only_with_no_listener_and_no_quiesce() {
let cfg = SnapshotTriggerConfig {
on_listener: true,
..Default::default()
};
let f = cfg
.evaluate(&TriggerSignals {
listener_count: 1,
workload_parked: true,
..sig()
})
.unwrap();
assert_eq!(f.reason, "listener-ready");
let f = cfg
.evaluate(&TriggerSignals {
listener_count: 0,
workload_parked: true,
..sig()
})
.unwrap();
assert_eq!(f.reason, "workload-parked");
assert!(!f.needs_quiesce);
}
#[test]
fn wall_clock_is_the_last_resort() {
let cfg = SnapshotTriggerConfig {
on_listener: true,
after_ms: Some(7000),
..Default::default()
};
assert_eq!(
cfg.evaluate(&TriggerSignals {
elapsed_ms: 6999,
..sig()
}),
None
);
let f = cfg
.evaluate(&TriggerSignals {
elapsed_ms: 7000,
..sig()
})
.unwrap();
assert_eq!(f.reason, "wall-clock");
assert!(!f.needs_quiesce);
}
#[test]
fn disabled_triggers_never_fire() {
let cfg = SnapshotTriggerConfig {
on_listener: false,
..Default::default()
};
assert_eq!(
cfg.evaluate(&TriggerSignals {
listener_count: 5,
workload_parked: true,
..sig()
}),
None
);
}
}