Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: builder_without_max_(times|delay) #160

Merged
merged 5 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions backon/src/backoff/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ impl ConstantBuilder {
self.jitter = true;
self
}

/// Set no max times for the backoff.
///
/// The backoff will not stop by itself.
///
/// _The backoff could stop reaching `usize::MAX` attempts but this is **unrealistic**._
pub fn without_max_times(mut self) -> Self {
self.max_times = None;
self
}
}

impl BackoffBuilder for ConstantBuilder {
Expand Down Expand Up @@ -139,32 +149,32 @@ mod tests {

#[test]
fn test_constant_default() {
let mut exp = ConstantBuilder::default().build();
let mut it = ConstantBuilder::default().build();

assert_eq!(Some(Duration::from_secs(1)), exp.next());
assert_eq!(Some(Duration::from_secs(1)), exp.next());
assert_eq!(Some(Duration::from_secs(1)), exp.next());
assert_eq!(None, exp.next());
assert_eq!(Some(Duration::from_secs(1)), it.next());
assert_eq!(Some(Duration::from_secs(1)), it.next());
assert_eq!(Some(Duration::from_secs(1)), it.next());
assert_eq!(None, it.next());
}

#[test]
fn test_constant_with_delay() {
let mut exp = ConstantBuilder::default()
let mut it = ConstantBuilder::default()
.with_delay(Duration::from_secs(2))
.build();

assert_eq!(Some(Duration::from_secs(2)), exp.next());
assert_eq!(Some(Duration::from_secs(2)), exp.next());
assert_eq!(Some(Duration::from_secs(2)), exp.next());
assert_eq!(None, exp.next());
assert_eq!(Some(Duration::from_secs(2)), it.next());
assert_eq!(Some(Duration::from_secs(2)), it.next());
assert_eq!(Some(Duration::from_secs(2)), it.next());
assert_eq!(None, it.next());
}

#[test]
fn test_constant_with_times() {
let mut exp = ConstantBuilder::default().with_max_times(1).build();
let mut it = ConstantBuilder::default().with_max_times(1).build();

assert_eq!(Some(Duration::from_secs(1)), exp.next());
assert_eq!(None, exp.next());
assert_eq!(Some(Duration::from_secs(1)), it.next());
assert_eq!(None, it.next());
}

#[test]
Expand All @@ -175,4 +185,13 @@ mod tests {
fastrand::seed(7);
assert!(dur > Duration::from_secs(1));
}

#[test]
fn test_constant_without_max_times() {
let mut it = ConstantBuilder::default().without_max_times().build();

for _ in 0..10_000 {
assert_eq!(Some(Duration::from_secs(1)), it.next());
}
}
}
51 changes: 51 additions & 0 deletions backon/src/backoff/exponential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,33 @@ impl ExponentialBuilder {
self
}

/// Set no maximum delay for the backoff.
///
/// The delay will keep increasing.
///
/// _The delay will saturate at `Duration::MAX` which is an **unrealistic** delay._
pub fn without_max_delay(mut self) -> Self {
self.max_delay = None;
self
}

/// Set the maximum number of attempts for the current backoff.
///
/// The backoff will stop if the maximum number of attempts is reached.
pub fn with_max_times(mut self, max_times: usize) -> Self {
self.max_times = Some(max_times);
self
}

/// Set no maximum number of attempts for the current backoff.
///
/// The backoff will not stop by itself.
///
/// _The backoff could stop reaching `usize::MAX` attempts but this is **unrealistic**._
pub fn without_max_times(mut self) -> Self {
self.max_times = None;
self
}
}

impl BackoffBuilder for ExponentialBuilder {
Expand Down Expand Up @@ -246,6 +266,21 @@ mod tests {
assert_eq!(None, exp.next());
}

#[test]
fn test_exponential_no_max_times_with_default() {
let mut exp = ExponentialBuilder::default()
.with_min_delay(Duration::from_secs(1))
.with_factor(1_f32)
.without_max_times()
.build();

// to fully test we would need to call this `usize::MAX`
// which seems unreasonable for a test as it would take too long...
for _ in 0..10_000 {
assert_eq!(Some(Duration::from_secs(1)), exp.next());
}
}

#[test]
fn test_exponential_max_delay_with_default() {
let mut exp = ExponentialBuilder::default()
Expand All @@ -258,6 +293,22 @@ mod tests {
assert_eq!(None, exp.next());
}

#[test]
fn test_exponential_no_max_delay_with_default() {
let mut exp = ExponentialBuilder::default()
.with_min_delay(Duration::from_secs(1))
.with_factor(10_000_000_000_f32)
.without_max_delay()
.with_max_times(4)
.build();

assert_eq!(Some(Duration::from_secs(1)), exp.next());
assert_eq!(Some(Duration::from_secs(10_000_000_000)), exp.next());
assert_eq!(Some(Duration::MAX), exp.next());
assert_eq!(Some(Duration::MAX), exp.next());
assert_eq!(None, exp.next());
}

#[test]
fn test_exponential_max_delay_without_default_1() {
let mut exp = ExponentialBuilder {
Expand Down
57 changes: 56 additions & 1 deletion backon/src/backoff/fibonacci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,33 @@ impl FibonacciBuilder {
self
}

/// Set no maximum delay for the backoff.
///
/// The delay will keep increasing.
///
/// _The delay will saturate at `Duration::MAX` which is an **unrealistic** delay._
pub fn without_max_delay(mut self) -> Self {
self.max_delay = None;
self
}

/// Set the maximum number of attempts for the current backoff.
///
/// The backoff will stop if the maximum number of attempts is reached.
pub fn with_max_times(mut self, max_times: usize) -> Self {
self.max_times = Some(max_times);
self
}

/// Set no maximum number of attempts for the current backoff.
///
/// The backoff will not stop by itself.
///
/// _The backoff could stop reaching `usize::MAX` attempts but this is **unrealistic**._
pub fn without_max_times(mut self) -> Self {
self.max_times = None;
self
}
}

impl BackoffBuilder for FibonacciBuilder {
Expand Down Expand Up @@ -153,7 +173,7 @@ impl Iterator for FibonacciBackoff {
// If current delay larger than max delay, we should stop increment anymore.
if next < self.max_delay.unwrap_or(Duration::MAX) {
if let Some(prev) = self.previous_delay {
next += prev;
next = next.saturating_add(prev);
self.current_delay = Some(next);
}
self.previous_delay = Some(cur);
Expand Down Expand Up @@ -235,6 +255,27 @@ mod tests {
assert_eq!(None, fib.next());
}

#[test]
fn test_fibonacci_no_max_delay() {
let mut fib = FibonacciBuilder::default()
.with_max_times(4)
.with_min_delay(Duration::from_secs(10_000_000_000_000_000_000))
.without_max_delay()
.build();

assert_eq!(
Some(Duration::from_secs(10_000_000_000_000_000_000)),
fib.next()
);
assert_eq!(
Some(Duration::from_secs(10_000_000_000_000_000_000)),
fib.next()
);
assert_eq!(Some(Duration::MAX), fib.next());
assert_eq!(Some(Duration::MAX), fib.next());
assert_eq!(None, fib.next());
}

#[test]
fn test_fibonacci_max_times() {
let mut fib = FibonacciBuilder::default().with_max_times(6).build();
Expand All @@ -247,4 +288,18 @@ mod tests {
assert_eq!(Some(Duration::from_secs(8)), fib.next());
assert_eq!(None, fib.next());
}

#[test]
fn test_fibonacci_no_max_times() {
let mut fib = FibonacciBuilder::default()
.with_min_delay(Duration::from_secs(0))
.without_max_times()
.build();

// to fully test we would need to call this `usize::MAX`
// which seems unreasonable for a test as it would take too long...
for _ in 0..10_000 {
assert_eq!(Some(Duration::from_secs(0)), fib.next());
}
}
}
Loading