Skip to main content

cloud_sdk/action_polling/
context.rs

1use crate::rate_limit::{RateLimit, WallClockTimestamp};
2use crate::retry::MonotonicDuration;
3
4use super::{ProgressChange, ProgressObservation};
5
6/// Caller decision made independently from delay policy.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum PollControl {
9    /// Continue the bounded workflow.
10    Continue,
11    /// Cancel before another request is admitted.
12    Cancel,
13}
14
15/// Provider-owned wall-clock telemetry carried without driving local budgets.
16#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
17pub struct ProviderTimeObservation {
18    observed_at: Option<WallClockTimestamp>,
19    expires_at: Option<WallClockTimestamp>,
20}
21
22impl ProviderTimeObservation {
23    /// Creates coherent provider timestamps.
24    pub const fn new(
25        observed_at: Option<WallClockTimestamp>,
26        expires_at: Option<WallClockTimestamp>,
27    ) -> Result<Self, ProviderTimeError> {
28        if let (Some(observed), Some(expires)) = (observed_at, expires_at)
29            && expires.get() < observed.get()
30        {
31            return Err(ProviderTimeError::ExpiryBeforeObservation);
32        }
33        Ok(Self {
34            observed_at,
35            expires_at,
36        })
37    }
38
39    /// Returns the provider-reported observation timestamp.
40    #[must_use]
41    pub const fn observed_at(self) -> Option<WallClockTimestamp> {
42        self.observed_at
43    }
44
45    /// Returns the provider-reported expiry timestamp.
46    #[must_use]
47    pub const fn expires_at(self) -> Option<WallClockTimestamp> {
48        self.expires_at
49    }
50}
51
52/// Invalid provider wall-clock telemetry.
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum ProviderTimeError {
55    /// The provider expiry precedes its observation timestamp.
56    ExpiryBeforeObservation,
57}
58
59impl_static_error!(ProviderTimeError,
60    Self::ExpiryBeforeObservation => "provider expiry precedes its observation timestamp",
61);
62
63/// Redacted context supplied to caller-owned backoff policy.
64#[derive(Clone, Copy, Debug, Eq, PartialEq)]
65pub struct PollContext {
66    pub(crate) observation: u32,
67    pub(crate) progress: ProgressObservation,
68    pub(crate) progress_change: ProgressChange,
69    pub(crate) rate_limit: Option<RateLimit>,
70    pub(crate) provider_time: ProviderTimeObservation,
71}
72
73impl PollContext {
74    /// Returns the one-based accepted observation count.
75    #[must_use]
76    pub const fn observation(self) -> u32 {
77        self.observation
78    }
79
80    /// Returns provider progress without inferring missing values.
81    #[must_use]
82    pub const fn progress(self) -> ProgressObservation {
83        self.progress
84    }
85
86    /// Returns the validated progress transition.
87    #[must_use]
88    pub const fn progress_change(self) -> ProgressChange {
89        self.progress_change
90    }
91
92    /// Returns provider quota telemetry when supplied.
93    #[must_use]
94    pub const fn rate_limit(self) -> Option<RateLimit> {
95        self.rate_limit
96    }
97
98    /// Returns provider wall-clock telemetry.
99    #[must_use]
100    pub const fn provider_time(self) -> ProviderTimeObservation {
101        self.provider_time
102    }
103}
104
105/// Next caller action before another provider request.
106#[derive(Clone, Copy, Debug, Eq, PartialEq)]
107pub enum PollRequestStep {
108    /// One provider action request is admitted now.
109    Request,
110    /// Wait this monotonic duration before asking again.
111    Delay(MonotonicDuration),
112    /// Caller cancellation made the workflow terminal.
113    Cancelled,
114    /// The monotonic elapsed budget made the workflow terminal.
115    TimedOut,
116}