Skip to main content

dex_sdk/
retry_policy.rs

1// Copyright (c) 2026 Super Durable, Inc.
2//
3// Licensed under the Sustainable Use License 1.0.
4// You may not use this file except in compliance with the License.
5// See the LICENSE file in the repository root.
6//
7// SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
8
9use std::time::Duration;
10
11#[derive(Clone, Debug, Default, PartialEq)]
12/// Overrides Dex retry timing for a Flow, `wait_for`, or `execute` operation.
13///
14/// Unset fields use server defaults. Intervals and total duration use [`Duration`]; maximum
15/// attempts counts the initial attempt. A zero maximum attempts value uses the server behavior.
16///
17/// Step retries default to a one-second initial interval, a multiplier of 2, a 100-second
18/// maximum interval, unlimited attempts, and four hours of total duration. Zero values select
19/// those defaults. A maximum of one disables retries. Non-retryable handler failures do not retry.
20///
21/// Changed in 1.35.0: a Step's total duration starts at its first hand-out to a Worker.
22/// It only gates scheduling another retry after failure; it never interrupts a running attempt.
23/// Method and heartbeat timeouts still apply to that attempt. Initial queue and lock waits do
24/// not consume the budget. Later backoff and queue waits do. A scheduled retry can start after
25/// the budget expires. Gracefully returning attempt one resets the budget's start only when no
26/// execution of that attempt may have run.
27///
28/// Use this policy for Step methods. The Server does not support whole-Flow retry. It rejects
29/// [`crate::StartFlowOptions::retry_policy`] with INVALID_ARGUMENT and rejects a SubFlow that
30/// sets [`crate::SubFlowOptions::retry_policy`] as invalid input. Use Step retry policies instead.
31/// Duration values must fit signed 32-bit whole seconds when submitted. Builders take ownership
32/// and return the updated policy; validation occurs when the options are mapped for a request.
33///
34/// # Examples
35///
36/// ```
37/// use dex_sdk::RetryPolicy;
38/// use std::time::Duration;
39///
40/// let retry = RetryPolicy::new()
41///     .initial_interval(Duration::from_secs(1))
42///     .backoff_coefficient(2.0)
43///     .maximum_interval(Duration::from_secs(30))
44///     .maximum_attempts(5);
45/// ```
46pub struct RetryPolicy {
47    pub(crate) initial_interval: Option<Duration>,
48    pub(crate) backoff_coefficient: Option<f64>,
49    pub(crate) maximum_interval: Option<Duration>,
50    pub(crate) maximum_attempts: Option<u32>,
51    pub(crate) total_duration: Option<Duration>,
52}
53
54impl RetryPolicy {
55    /// Creates an empty policy that preserves every server default.
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    /// Sets the delay before the first retry.
61    ///
62    /// Zero uses one second. The value must fit signed 32-bit whole seconds.
63    pub fn initial_interval(mut self, value: Duration) -> Self {
64        self.initial_interval = Some(value);
65        self
66    }
67
68    /// Sets the multiplier applied to each successive retry interval.
69    ///
70    /// Zero uses 2. The retry delay grows by this multiplier until the maximum interval.
71    pub fn backoff_coefficient(mut self, value: f64) -> Self {
72        self.backoff_coefficient = Some(value);
73        self
74    }
75
76    /// Caps the delay between retries.
77    ///
78    /// Zero uses 100 seconds. The value must fit signed 32-bit whole seconds.
79    pub fn maximum_interval(mut self, value: Duration) -> Self {
80        self.maximum_interval = Some(value);
81        self
82    }
83
84    /// Sets the total attempt limit, including the initial attempt.
85    ///
86    /// Zero allows unlimited attempts within the total-duration budget for Steps. One disables retries.
87    /// Values above the signed 32-bit maximum fail when the policy is submitted.
88    pub fn maximum_attempts(mut self, value: u32) -> Self {
89        self.maximum_attempts = Some(value);
90        self
91    }
92
93    /// Sets the elapsed-time budget used to decide whether to retry a failed Step attempt.
94    ///
95    /// For Steps, time starts when Dex first hands the Step to a Worker. Dex checks this budget
96    /// only after an attempt fails; expiration never ends a running attempt. Unset uses the Server
97    /// default of four hours. Zero also selects that default. `value` uses [`Duration`] and is
98    /// serialized in seconds; invalid durations fail when the policy is submitted. Returns this
99    /// policy with the budget applied.
100    ///
101    /// Changed in 1.35.0: queueing before the first hand-out is excluded, and this budget no
102    /// longer shortens a running attempt's method timeout. See [`RetryPolicy`] for retry queueing.
103    ///
104    /// ```
105    /// use dex_sdk::RetryPolicy;
106    /// use std::time::Duration;
107    /// let retry = RetryPolicy::new().total_duration(Duration::from_secs(60));
108    /// ```
109    pub fn total_duration(mut self, value: Duration) -> Self {
110        self.total_duration = Some(value);
111        self
112    }
113}