pyth_lazer_client/backoff.rs
1//! Exponential backoff implementation for Pyth Lazer client.
2//!
3//! This module provides a wrapper around the [`backoff`] crate's exponential backoff functionality,
4//! offering a simplified interface tailored for Pyth Lazer client operations.
5
6use std::time::Duration;
7
8use backoff::{
9 default::{INITIAL_INTERVAL_MILLIS, MAX_INTERVAL_MILLIS, MULTIPLIER, RANDOMIZATION_FACTOR},
10 ExponentialBackoff, ExponentialBackoffBuilder,
11};
12
13/// A wrapper around the backoff crate's exponential backoff configuration.
14///
15/// This struct encapsulates the parameters needed to configure exponential backoff
16/// behavior and can be converted into the backoff crate's [`ExponentialBackoff`] type.
17#[derive(Debug)]
18pub struct PythLazerExponentialBackoff {
19 /// The initial retry interval.
20 initial_interval: Duration,
21 /// The randomization factor to use for creating a range around the retry interval.
22 ///
23 /// A randomization factor of 0.5 results in a random period ranging between 50% below and 50%
24 /// above the retry interval.
25 randomization_factor: f64,
26 /// The value to multiply the current interval with for each retry attempt.
27 multiplier: f64,
28 /// The maximum value of the back off period. Once the retry interval reaches this
29 /// value it stops increasing.
30 max_interval: Duration,
31}
32
33impl From<PythLazerExponentialBackoff> for ExponentialBackoff {
34 fn from(val: PythLazerExponentialBackoff) -> Self {
35 ExponentialBackoffBuilder::default()
36 .with_initial_interval(val.initial_interval)
37 .with_randomization_factor(val.randomization_factor)
38 .with_multiplier(val.multiplier)
39 .with_max_interval(val.max_interval)
40 .with_max_elapsed_time(None)
41 .build()
42 }
43}
44
45/// Builder for [`PythLazerExponentialBackoff`].
46///
47/// Provides a fluent interface for configuring exponential backoff parameters
48/// with sensible defaults from the backoff crate.
49#[derive(Debug)]
50pub struct PythLazerExponentialBackoffBuilder {
51 initial_interval: Duration,
52 randomization_factor: f64,
53 multiplier: f64,
54 max_interval: Duration,
55}
56
57impl Default for PythLazerExponentialBackoffBuilder {
58 fn default() -> Self {
59 Self {
60 initial_interval: Duration::from_millis(INITIAL_INTERVAL_MILLIS),
61 randomization_factor: RANDOMIZATION_FACTOR,
62 multiplier: MULTIPLIER,
63 max_interval: Duration::from_millis(MAX_INTERVAL_MILLIS),
64 }
65 }
66}
67
68impl PythLazerExponentialBackoffBuilder {
69 /// Creates a new builder with default values.
70 pub fn new() -> Self {
71 Default::default()
72 }
73
74 /// Sets the initial retry interval.
75 ///
76 /// This is the starting interval for the first retry attempt.
77 pub fn with_initial_interval(&mut self, initial_interval: Duration) -> &mut Self {
78 self.initial_interval = initial_interval;
79 self
80 }
81
82 /// Sets the randomization factor to use for creating a range around the retry interval.
83 ///
84 /// A randomization factor of 0.5 results in a random period ranging between 50% below and 50%
85 /// above the retry interval. This helps avoid the "thundering herd" problem when multiple
86 /// clients retry at the same time.
87 pub fn with_randomization_factor(&mut self, randomization_factor: f64) -> &mut Self {
88 self.randomization_factor = randomization_factor;
89 self
90 }
91
92 /// Sets the value to multiply the current interval with for each retry attempt.
93 ///
94 /// A multiplier of 2.0 means each retry interval will be double the previous one.
95 pub fn with_multiplier(&mut self, multiplier: f64) -> &mut Self {
96 self.multiplier = multiplier;
97 self
98 }
99
100 /// Sets the maximum value of the back off period.
101 ///
102 /// Once the retry interval reaches this value it stops increasing, providing
103 /// an upper bound on the wait time between retries.
104 pub fn with_max_interval(&mut self, max_interval: Duration) -> &mut Self {
105 self.max_interval = max_interval;
106 self
107 }
108
109 /// Builds the [`PythLazerExponentialBackoff`] configuration.
110 pub fn build(&self) -> PythLazerExponentialBackoff {
111 PythLazerExponentialBackoff {
112 initial_interval: self.initial_interval,
113 randomization_factor: self.randomization_factor,
114 multiplier: self.multiplier,
115 max_interval: self.max_interval,
116 }
117 }
118}