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