cloud_sdk/action_polling/
backoff.rs1use crate::retry::MonotonicDuration;
2
3use super::{PollContext, ProgressChange};
4
5pub const MAX_BACKOFF_MULTIPLIER: u8 = 16;
7
8pub trait PollBackoff {
10 type Error;
12
13 fn delay(&mut self, context: PollContext) -> Result<MonotonicDuration, Self::Error>;
15}
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum ExponentialBackoffError {
20 ZeroDelay,
22 InitialExceedsMaximum,
24 InvalidMultiplier,
26}
27
28impl_static_error!(ExponentialBackoffError,
29 Self::ZeroDelay => "poll backoff delays must be nonzero",
30 Self::InitialExceedsMaximum => "initial poll backoff exceeds its maximum",
31 Self::InvalidMultiplier => "poll backoff multiplier is invalid",
32);
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub struct ExponentialBackoff {
37 initial: MonotonicDuration,
38 maximum: MonotonicDuration,
39 multiplier: u8,
40 next: MonotonicDuration,
41}
42
43impl ExponentialBackoff {
44 pub const fn new(
46 initial: MonotonicDuration,
47 maximum: MonotonicDuration,
48 multiplier: u8,
49 ) -> Result<Self, ExponentialBackoffError> {
50 if initial.get() == 0 || maximum.get() == 0 {
51 return Err(ExponentialBackoffError::ZeroDelay);
52 }
53 if initial.get() > maximum.get() {
54 return Err(ExponentialBackoffError::InitialExceedsMaximum);
55 }
56 if multiplier == 0 || multiplier > MAX_BACKOFF_MULTIPLIER {
57 return Err(ExponentialBackoffError::InvalidMultiplier);
58 }
59 Ok(Self {
60 initial,
61 maximum,
62 multiplier,
63 next: initial,
64 })
65 }
66
67 #[must_use]
69 pub const fn next_delay(self) -> MonotonicDuration {
70 self.next
71 }
72}
73
74impl PollBackoff for ExponentialBackoff {
75 type Error = core::convert::Infallible;
76
77 fn delay(&mut self, context: PollContext) -> Result<MonotonicDuration, Self::Error> {
78 if matches!(
79 context.progress_change(),
80 ProgressChange::Initial | ProgressChange::Advanced | ProgressChange::Reset
81 ) {
82 self.next = self.initial;
83 }
84 let selected = self.next;
85 let multiplied = selected
86 .get()
87 .saturating_mul(u64::from(self.multiplier))
88 .min(self.maximum.get());
89 self.next = MonotonicDuration::new(multiplied);
90 Ok(selected)
91 }
92}