Skip to content

Commit 8a0b82d

Browse files
committed
Add MaxAttemptsRetryPolicy
1 parent 0b0e5f9 commit 8a0b82d

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

src/util/retry.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use std::time::Duration;
55

66
/// A function that performs and retries the given operation according to a retry policy.
77
///
8+
/// **Caution**: A retry policy without the number of attempts capped by [`MaxAttemptsRetryPolicy`]
9+
/// decorator will result in infinite retries.
10+
///
811
/// **Example**
912
/// ```rust
1013
/// # use std::time::Duration;
@@ -16,7 +19,8 @@ use std::time::Duration;
1619
/// # Ok(42)
1720
/// # }
1821
/// #
19-
/// let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100));
22+
/// let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100))
23+
/// .with_max_attempts(5);
2024
///
2125
/// let result = retry(operation, &retry_policy);
2226
///```
@@ -57,6 +61,11 @@ pub trait RetryPolicy: Sized {
5761
///
5862
/// If `None` is returned then no further retry attempt is made.
5963
fn next_delay(&self, context: &RetryContext<Self::E>) -> Option<Duration>;
64+
65+
/// Returns a new `RetryPolicy` that respects the given maximum attempts.
66+
fn with_max_attempts(self, max_attempts: u32) -> MaxAttemptsRetryPolicy<Self> {
67+
MaxAttemptsRetryPolicy { inner_policy: self, max_attempts }
68+
}
6069
}
6170

6271
/// Represents the context of a retry operation.
@@ -103,3 +112,22 @@ impl<E: Error> RetryPolicy for ExponentialBackoffRetryPolicy<E> {
103112
Some(delay)
104113
}
105114
}
115+
116+
/// Decorates the given `RetryPolicy` to respect the given maximum attempts.
117+
pub struct MaxAttemptsRetryPolicy<T: RetryPolicy> {
118+
/// The underlying retry policy to use.
119+
inner_policy: T,
120+
/// The maximum number of attempts to retry.
121+
max_attempts: u32,
122+
}
123+
124+
impl<T: RetryPolicy> RetryPolicy for MaxAttemptsRetryPolicy<T> {
125+
type E = T::E;
126+
fn next_delay(&self, context: &RetryContext<Self::E>) -> Option<Duration> {
127+
if self.max_attempts == context.attempts_made {
128+
None
129+
} else {
130+
self.inner_policy.next_delay(context)
131+
}
132+
}
133+
}

0 commit comments

Comments
 (0)