use std::fmt;
use std::time::Duration;
#[derive(Debug, thiserror::Error)]
#[error("max restart intensity reached")]
pub struct MaxRestartIntensityReached;
#[derive(Debug, Clone, Copy)]
pub struct RestartIntensity {
pub max_restarts: usize,
pub within: Duration,
}
#[derive(Default, Debug)]
pub struct RestartStats(Vec<tokio::time::Instant>);
impl RestartIntensity {
pub fn new_stats(&self) -> RestartStats {
RestartStats(Vec::with_capacity(self.max_restarts + 1))
}
pub fn report_exit(
&self,
stats: &mut RestartStats,
now: tokio::time::Instant,
) -> Result<(), MaxRestartIntensityReached> {
let t_cutoff = now.checked_sub(self.within).unwrap_or(now);
stats.0.retain(|t| *t >= t_cutoff);
stats.0.push(now);
if stats.0.len() > self.max_restarts {
Err(MaxRestartIntensityReached)
} else {
Ok(())
}
}
}
impl Default for RestartIntensity {
fn default() -> Self {
Self {
max_restarts: 0,
within: Duration::MAX,
}
}
}
impl fmt::Display for RestartIntensity
where
Self: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}