1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
use std::{future::Future, time::Duration};
/// Retry configurations for establishing connections and sending messages.
/// Determines the retry behaviour of requests, by setting the back off strategy used.
#[derive(Clone, Debug, Copy)]
pub struct RetryConfig {
/// The initial retry interval.
///
/// This is the first delay before a retry, for establishing connections and sending messages.
/// The subsequent delay will be decided by the `retry_delay_multiplier`.
pub initial_retry_interval: Duration,
/// The maximum value of the back off period. Once the retry interval reaches this
/// value it stops increasing.
///
/// This is the longest duration we will have,
/// for establishing connections and sending messages.
/// Retrying continues even after the duration times have reached this duration.
/// The number of retries before that happens, will be decided by the `retry_delay_multiplier`.
/// The number of retries after that, will be decided by the `retrying_max_elapsed_time`.
pub max_retry_interval: Duration,
/// The value to multiply the current interval with for each retry attempt.
pub retry_delay_multiplier: f64,
/// The randomization factor to use for creating a range around the retry interval.
///
/// A randomization factor of 0.5 results in a random period ranging between 50% below and 50%
/// above the retry interval.
pub retry_delay_rand_factor: f64,
/// The maximum elapsed time after instantiating
///
/// Retrying continues until this time has elapsed.
/// The number of retries before that happens, will be decided by the other retry config options.
pub retrying_max_elapsed_time: Option<Duration>,
}
impl RetryConfig {
// Together with the default max and multiplier,
// default gives 5-6 retries in ~30 s total retry time.
/// Default for [`RetryConfig::max_retry_interval`] (500 ms).
pub const DEFAULT_INITIAL_RETRY_INTERVAL: Duration = Duration::from_millis(500);
/// Default for [`RetryConfig::max_retry_interval`] (15 s).
pub const DEFAULT_MAX_RETRY_INTERVAL: Duration = Duration::from_secs(15);
/// Default for [`RetryConfig::retry_delay_multiplier`] (x1.5).
pub const DEFAULT_RETRY_INTERVAL_MULTIPLIER: f64 = 1.5;
/// Default for [`RetryConfig::retry_delay_rand_factor`] (0.3).
pub const DEFAULT_RETRY_DELAY_RAND_FACTOR: f64 = 0.3;
/// Default for [`RetryConfig::retrying_max_elapsed_time`] (30 s).
pub const DEFAULT_RETRYING_MAX_ELAPSED_TIME: Duration = Duration::from_secs(30);
// Perform `op` and retry on errors as specified by this configuration.
//
// Note that `backoff::Error<E>` implements `From<E>` for any `E` by creating a
// `backoff::Error::Transient`, meaning that errors will be retried unless explicitly returning
// `backoff::Error::Permanent`.
pub fn retry<R, E, Fn, Fut>(self, op: Fn) -> impl Future<Output = Result<R, E>>
where
Fn: FnMut() -> Fut,
Fut: Future<Output = Result<R, backoff::Error<E>>>,
{
let backoff = backoff::ExponentialBackoff {
initial_interval: self.initial_retry_interval,
randomization_factor: self.retry_delay_rand_factor,
multiplier: self.retry_delay_multiplier,
max_interval: self.max_retry_interval,
max_elapsed_time: self.retrying_max_elapsed_time,
..Default::default()
};
backoff::future::retry(backoff, op)
}
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
initial_retry_interval: RetryConfig::DEFAULT_INITIAL_RETRY_INTERVAL,
max_retry_interval: RetryConfig::DEFAULT_MAX_RETRY_INTERVAL,
retry_delay_multiplier: RetryConfig::DEFAULT_RETRY_INTERVAL_MULTIPLIER,
retry_delay_rand_factor: RetryConfig::DEFAULT_RETRY_DELAY_RAND_FACTOR,
retrying_max_elapsed_time: Some(RetryConfig::DEFAULT_RETRYING_MAX_ELAPSED_TIME),
}
}
}