feat(supervisor): sliding retry-window tracker
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RetryWindow {
|
||||||
|
window: Duration,
|
||||||
|
cap: u32,
|
||||||
|
events: VecDeque<Instant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RetryWindow {
|
||||||
|
pub fn new(window: Duration, cap: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
cap,
|
||||||
|
events: VecDeque::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn record(&mut self, now: Instant) {
|
||||||
|
self.events.push_back(now);
|
||||||
|
self.prune(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cap_reached(&mut self, now: Instant) -> bool {
|
||||||
|
self.prune(now);
|
||||||
|
self.events.len() as u32 >= self.cap
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count(&mut self, now: Instant) -> u32 {
|
||||||
|
self.prune(now);
|
||||||
|
self.events.len() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prune(&mut self, now: Instant) {
|
||||||
|
while let Some(&front) = self.events.front() {
|
||||||
|
if now.duration_since(front) > self.window {
|
||||||
|
self.events.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn below_cap_not_reached() {
|
||||||
|
let mut w = RetryWindow::new(Duration::from_secs(60), 3);
|
||||||
|
let t = Instant::now();
|
||||||
|
w.record(t);
|
||||||
|
w.record(t);
|
||||||
|
assert!(!w.cap_reached(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn at_cap_reached() {
|
||||||
|
let mut w = RetryWindow::new(Duration::from_secs(60), 3);
|
||||||
|
let t = Instant::now();
|
||||||
|
w.record(t);
|
||||||
|
w.record(t);
|
||||||
|
w.record(t);
|
||||||
|
assert!(w.cap_reached(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn old_events_pruned() {
|
||||||
|
let mut w = RetryWindow::new(Duration::from_secs(60), 3);
|
||||||
|
let t0 = Instant::now();
|
||||||
|
w.record(t0);
|
||||||
|
w.record(t0);
|
||||||
|
w.record(t0);
|
||||||
|
let t1 = t0 + Duration::from_secs(61);
|
||||||
|
assert_eq!(w.count(t1), 0);
|
||||||
|
assert!(!w.cap_reached(t1));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user