Fix RestartStrategy::timeout < 1s (#265)

This commit is contained in:
nicolaiunrein 2020-08-20 21:14:52 +02:00 committed by GitHub
parent 6a9f11eb5e
commit 75904cfe43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 19 deletions

View File

@ -189,13 +189,13 @@ pub enum RestartPolicy {
///
/// The default strategy used is `ActorRestartStrategy::Immediate`
/// with the `RestartPolicy::Always` restart policy.
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub struct RestartStrategy {
restart_policy: RestartPolicy,
strategy: ActorRestartStrategy,
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
/// The strategy for restating an actor as far as it
/// returned an failure.
///
@ -219,10 +219,31 @@ pub enum ActorRestartStrategy {
/// An initial delay before the restarting an actor.
timeout: Duration,
/// Defines a multiplier how fast the timeout will be increasing.
multiplier: u64,
multiplier: f64,
},
}
impl ActorRestartStrategy {
/// Calculate the expected restart delay for given strategy after n restarts.
pub fn calculate(&self, restarts_count: usize) -> Option<Duration> {
match *self {
ActorRestartStrategy::LinearBackOff { timeout } => {
let delay = timeout.mul_f64(restarts_count as f64);
Some(timeout + delay)
}
ActorRestartStrategy::ExponentialBackOff {
timeout,
multiplier,
} => {
let factor = multiplier * restarts_count as f64;
let delay = timeout.mul_f64(factor);
Some(timeout + delay)
}
_ => None,
}
}
}
impl Supervisor {
pub(crate) fn new(bcast: Broadcast) -> Self {
debug!("Supervisor({}): Initializing.", bcast.id());
@ -733,7 +754,7 @@ impl Supervisor {
/// .with_actor_restart_strategy(
/// ActorRestartStrategy::ExponentialBackOff {
/// timeout: Duration::from_millis(5000),
/// multiplier: 3,
/// multiplier: 3.0,
/// }
/// )
/// )
@ -1892,21 +1913,9 @@ impl RestartStrategy {
}
pub(crate) async fn apply_strategy(&self, restarts_count: usize) {
match self.strategy {
ActorRestartStrategy::LinearBackOff { timeout } => {
let start_in = timeout.as_secs() + (timeout.as_secs() * restarts_count as u64);
Delay::new(Duration::from_secs(start_in)).await;
}
ActorRestartStrategy::ExponentialBackOff {
timeout,
multiplier,
} => {
let start_in =
timeout.as_secs() + (timeout.as_secs() * multiplier * restarts_count as u64);
Delay::new(Duration::from_secs(start_in)).await;
}
_ => {}
};
if let Some(dur) = self.strategy.calculate(restarts_count) {
Delay::new(dur).await;
}
}
}

View File

@ -43,3 +43,61 @@ fn override_restart_strategy_and_policy() {
assert_eq!(restart_strategy.restart_policy(), policy);
assert_eq!(restart_strategy.strategy(), strategy);
}
#[test]
fn calculate_immediate_strategy() {
let strategy = ActorRestartStrategy::Immediate;
assert_eq!(strategy.calculate(0), None);
assert_eq!(strategy.calculate(1), None);
assert_eq!(strategy.calculate(100), None);
}
#[test]
fn calculate_linear_strategy() {
let strategy = ActorRestartStrategy::LinearBackOff {
timeout: Duration::from_millis(100),
};
assert_eq!(strategy.calculate(0), Some(Duration::from_millis(100)));
assert_eq!(
strategy.calculate(1),
Some(Duration::from_millis(100 + 1 * 100))
);
assert_eq!(
strategy.calculate(99),
Some(Duration::from_millis(100 + 99 * 100))
);
}
#[test]
fn calculate_exp_strategy_with_multiplier_zero() {
let strategy = ActorRestartStrategy::ExponentialBackOff {
timeout: Duration::from_millis(100),
multiplier: 0.0,
};
assert_eq!(strategy.calculate(0), Some(Duration::from_millis(100)));
assert_eq!(strategy.calculate(1), Some(Duration::from_millis(100)));
assert_eq!(strategy.calculate(100), Some(Duration::from_millis(100)));
}
#[test]
fn calculate_exp_strategy_with_multiplier_non_zero() {
let strategy = ActorRestartStrategy::ExponentialBackOff {
timeout: Duration::from_millis(100),
multiplier: 5.0,
};
assert_eq!(strategy.calculate(0), Some(Duration::from_millis(100)));
assert_eq!(
strategy.calculate(1),
Some(Duration::from_millis(100 + 1 * 5 * 100))
);
assert_eq!(
strategy.calculate(99),
Some(Duration::from_millis(100 + 99 * 5 * 100))
);
}