Skip to main content

relay_server/utils/
retry.rs

1use std::time::Duration;
2
3use backon::BackoffBuilder;
4use backon::ExponentialBackoff;
5use backon::ExponentialBuilder;
6
7/// Backoff multiplier (1.5 which is 50% increase per backoff).
8const DEFAULT_MULTIPLIER: f32 = 1.5;
9/// Initial interval in milliseconds (1 second).
10const INITIAL_INTERVAL: Duration = Duration::from_millis(1000);
11
12/// A retry interval generator that increases timeouts with exponential backoff.
13#[derive(Debug)]
14pub struct RetryBackoff {
15    builder: ExponentialBuilder,
16    backoff: ExponentialBackoff,
17    attempt: usize,
18}
19
20impl RetryBackoff {
21    /// Creates a new retry backoff based on configured thresholds.
22    pub fn new(max_interval: Duration) -> Self {
23        let builder = ExponentialBuilder::new()
24            .with_factor(DEFAULT_MULTIPLIER)
25            .with_min_delay(INITIAL_INTERVAL)
26            .with_max_delay(max_interval)
27            .without_max_times();
28
29        RetryBackoff {
30            backoff: builder.build(),
31            builder,
32            attempt: 0,
33        }
34    }
35
36    /// Resets this backoff to its initial state.
37    pub fn reset(&mut self) {
38        self.backoff = self.builder.build();
39        self.attempt = 0;
40    }
41
42    /// Indicates whether a backoff attempt has started.
43    pub fn started(&self) -> bool {
44        self.attempt > 0
45    }
46
47    /// Returns the number of the retry attempt.
48    pub fn attempt(&self) -> usize {
49        self.attempt
50    }
51
52    /// Returns the next backoff duration.
53    pub fn next_backoff(&mut self) -> Duration {
54        let duration = match self.attempt {
55            0 => Duration::ZERO,
56            _ => self.backoff.next().unwrap(),
57        };
58
59        self.attempt += 1;
60        duration
61    }
62}