use crate::{SupervisorError, SupervisorResult};
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RestartMode {
Never,
OnFailure,
Always,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RestartPolicy {
pub mode: RestartMode,
pub restart_budget: u32,
pub restart_window: Duration,
pub backoff: Duration,
pub jitter: Duration,
pub shutdown_timeout: Duration,
}
impl RestartPolicy {
pub fn never() -> Self {
Self {
mode: RestartMode::Never,
restart_budget: 0,
restart_window: Duration::from_secs(600),
backoff: Duration::ZERO,
jitter: Duration::ZERO,
shutdown_timeout: Duration::from_secs(10),
}
}
pub fn bounded(restart_budget: u32, restart_window: Duration) -> SupervisorResult<Self> {
let policy = Self {
mode: RestartMode::OnFailure,
restart_budget,
restart_window,
backoff: Duration::from_millis(100),
jitter: Duration::from_millis(50),
shutdown_timeout: Duration::from_secs(10),
};
policy.validate()?;
Ok(policy)
}
pub fn with_backoff(mut self, backoff: Duration, jitter: Duration) -> Self {
self.backoff = backoff;
self.jitter = jitter;
self
}
pub fn with_shutdown_timeout(mut self, shutdown_timeout: Duration) -> Self {
self.shutdown_timeout = shutdown_timeout;
self
}
pub fn validate(&self) -> SupervisorResult<()> {
if self.mode != RestartMode::Never
&& (self.restart_budget == 0 || self.restart_window.is_zero())
{
return Err(SupervisorError::InvalidConfiguration(
"automatic restart requires a non-zero budget and window".to_string(),
));
}
if self.shutdown_timeout.is_zero() {
return Err(SupervisorError::InvalidConfiguration(
"shutdown_timeout must be greater than zero".to_string(),
));
}
Ok(())
}
}
impl Default for RestartPolicy {
fn default() -> Self {
Self {
mode: RestartMode::OnFailure,
restart_budget: 5,
restart_window: Duration::from_secs(600),
backoff: Duration::from_millis(100),
jitter: Duration::from_millis(50),
shutdown_timeout: Duration::from_secs(10),
}
}
}