Skip to content

Commit 0b0e5f9

Browse files
committed
Add ExponentialBackoffRetryPolicy
1 parent d00287c commit 0b0e5f9

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

src/util/retry.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
use std::error::Error;
22
use std::future::Future;
3+
use std::marker::PhantomData;
34
use std::time::Duration;
45

56
/// A function that performs and retries the given operation according to a retry policy.
7+
///
8+
/// **Example**
9+
/// ```rust
10+
/// # use std::time::Duration;
11+
/// # use vss_client::error::VssError;
12+
/// # use vss_client::util::retry::{ExponentialBackoffRetryPolicy, retry, RetryPolicy};
13+
/// #
14+
/// # async fn operation() -> Result<i32, VssError> {
15+
/// # tokio::time::sleep(Duration::from_millis(10)).await;
16+
/// # Ok(42)
17+
/// # }
18+
/// #
19+
/// let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100));
20+
///
21+
/// let result = retry(operation, &retry_policy);
22+
///```
623
pub async fn retry<R, F, Fut, T, E>(mut operation: F, retry_policy: &R) -> Result<T, E>
724
where
825
R: RetryPolicy<E = E>,
@@ -58,3 +75,31 @@ pub struct RetryContext<'a, E: Error> {
5875
/// The error encountered in the previous attempt.
5976
error: &'a E,
6077
}
78+
79+
/// The exponential backoff strategy is a retry approach that doubles the delay between retries.
80+
/// A combined exponential backoff and jitter strategy is recommended that is ["Exponential Backoff and Jitter"](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/).
81+
/// This is helpful to avoid [Thundering Herd Problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).
82+
pub struct ExponentialBackoffRetryPolicy<E> {
83+
/// The base delay duration for the backoff algorithm. First retry is `base_delay` after first attempt.
84+
base_delay: Duration,
85+
phantom: PhantomData<E>,
86+
}
87+
88+
impl<E: Error> ExponentialBackoffRetryPolicy<E> {
89+
/// Constructs a new instance using `base_delay`.
90+
///
91+
/// `base_delay` is the base delay duration for the backoff algorithm. First retry is `base_delay`
92+
/// after first attempt.
93+
pub fn new(base_delay: Duration) -> ExponentialBackoffRetryPolicy<E> {
94+
Self { base_delay, phantom: PhantomData }
95+
}
96+
}
97+
98+
impl<E: Error> RetryPolicy for ExponentialBackoffRetryPolicy<E> {
99+
type E = E;
100+
fn next_delay(&self, context: &RetryContext<Self::E>) -> Option<Duration> {
101+
let backoff_factor = 2_u32.pow(context.attempts_made) - 1;
102+
let delay = self.base_delay * backoff_factor;
103+
Some(delay)
104+
}
105+
}

0 commit comments

Comments
 (0)