Skip to content

Commit

Permalink
Add a configurable multiplication factor in Exponential delay
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickLerner committed Aug 14, 2020
1 parent 2cbfe10 commit 2c156fd
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
39 changes: 33 additions & 6 deletions src/delay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,24 @@ use rand::{
/// Each retry increases the delay since the last exponentially.
#[derive(Debug)]
pub struct Exponential {
base: u64,
current: u64,
factor: f64,
}

impl Exponential {
/// Create a new `Exponential` using the given millisecond duration as the initial delay.
pub fn from_millis(base: u64) -> Self {
Exponential {
base,
current: base,
factor: base as f64,
}
}

/// Create a new `Exponential` using the given millisecond duration as the initial delay and a variable multiplication factor.
pub fn from_millis_with_factor(base: u64, factor: f64) -> Self {
Exponential {
current: base,
factor,
}
}
}
Expand All @@ -34,11 +42,12 @@ impl Iterator for Exponential {
fn next(&mut self) -> Option<Duration> {
let duration = Duration::from_millis(self.current);

if let Some(next) = self.current.checked_mul(self.base) {
self.current = next;
let next = (self.current as f64) * self.factor;
self.current = if next > (U64_MAX as f64) {
U64_MAX
} else {
self.current = U64_MAX;
}
next as u64
};

Some(duration)
}
Expand All @@ -50,6 +59,24 @@ impl From<Duration> for Exponential {
}
}

#[test]
fn exponential_with_factor() {
let mut iter = Exponential::from_millis_with_factor(1000, 2.0);
assert_eq!(iter.next(), Some(Duration::from_millis(1000)));
assert_eq!(iter.next(), Some(Duration::from_millis(2000)));
assert_eq!(iter.next(), Some(Duration::from_millis(4000)));
assert_eq!(iter.next(), Some(Duration::from_millis(8000)));
assert_eq!(iter.next(), Some(Duration::from_millis(16000)));
assert_eq!(iter.next(), Some(Duration::from_millis(32000)));
}

#[test]
fn exponential_overflow() {
let mut iter = Exponential::from_millis(U64_MAX);
assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX)));
assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX)));
}

/// Each retry uses a delay which is the sum of the two previous delays.
///
/// Depending on the problem at hand, a fibonacci delay strategy might
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ impl<E> Display for Error<E>
where
E: StdError,
{
#[allow(deprecated)]
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
write!(formatter, "{}", self.description())
}
Expand All @@ -212,6 +213,7 @@ impl<E> StdError for Error<E>
where
E: StdError,
{
#[allow(deprecated)]
fn description(&self) -> &str {
match *self {
Error::Operation { ref error, .. } => error.description(),
Expand Down Expand Up @@ -339,6 +341,23 @@ mod tests {
assert_eq!(value, 2);
}

#[test]
fn succeeds_with_exponential_delay_with_factor() {
let mut collection = vec![1, 2].into_iter();

let value = retry(
Exponential::from_millis_with_factor(1000, 2.0),
|| match collection.next() {
Some(n) if n == 2 => Ok(n),
Some(_) => Err("not 2"),
None => Err("not 2"),
},
)
.unwrap();

assert_eq!(value, 2);
}

#[test]
fn succeeds_with_ranged_delay() {
let mut collection = vec![1, 2].into_iter();
Expand Down

0 comments on commit 2c156fd

Please sign in to comment.