retry_policy/policies/google_cloud_workflows/
http.rs

1use retry_backoff::backoffs::google_cloud_workflows::Backoff;
2use retry_predicate::predicates::FnPredicate;
3
4use super::Policy;
5
6/// [Object: http.default_retry](https://cloud.google.com/workflows/docs/reference/stdlib/http/default_retry)
7pub fn default_retry() -> Policy<Error> {
8    Policy::new(
9        FnPredicate::from(default_retry_predicate),
10        5,
11        Backoff::default(),
12    )
13}
14
15/// [Object: http.default_retry_non_idempotent](https://cloud.google.com/workflows/docs/reference/stdlib/http/default_retry_non_idempotent)
16pub fn default_retry_non_idempotent() -> Policy<Error> {
17    Policy::new(
18        FnPredicate::from(default_retry_predicate_non_idempotent),
19        5,
20        Backoff::default(),
21    )
22}
23
24/// [Function: http.default_retry_predicate](https://cloud.google.com/workflows/docs/reference/stdlib/http/default_retry_predicate)
25pub fn default_retry_predicate(err: &Error) -> bool {
26    matches!(
27        err,
28        Error::TooManyRequests {
29            retry_after_delay_seconds: _
30        } | &Error::BadGateway
31            | Error::ServiceUnavailable {
32                retry_after_delay_seconds: _
33            }
34            | &Error::GatewayTimeout
35            | Error::ConnectionError
36            | Error::TimeoutError
37    )
38}
39
40/// [Function: http.default_retry_predicate_non_idempotent](https://cloud.google.com/workflows/docs/reference/stdlib/http/default_retry_predicate_non_idempotent)
41pub fn default_retry_predicate_non_idempotent(err: &Error) -> bool {
42    matches!(
43        err,
44        Error::TooManyRequests {
45            retry_after_delay_seconds: _
46        } | Error::ServiceUnavailable {
47            retry_after_delay_seconds: _
48        }
49    )
50}
51
52//
53#[derive(Debug)]
54pub enum Error {
55    /// 429
56    TooManyRequests {
57        /// [Ref](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After)
58        retry_after_delay_seconds: Option<usize>,
59    },
60    /// 502
61    BadGateway,
62    /// 503
63    ServiceUnavailable {
64        /// [Ref](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After)
65        retry_after_delay_seconds: Option<usize>,
66    },
67    /// 504
68    GatewayTimeout,
69    ConnectionError,
70    TimeoutError,
71    Other,
72}
73
74impl core::fmt::Display for Error {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        write!(f, "{self:?}")
77    }
78}
79
80impl core::error::Error for Error {}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_default_retry() {
88        let policy = default_retry();
89        for err in &[
90            Error::TooManyRequests {
91                retry_after_delay_seconds: None,
92            },
93            Error::BadGateway,
94            Error::ServiceUnavailable {
95                retry_after_delay_seconds: None,
96            },
97            Error::GatewayTimeout,
98            Error::ConnectionError,
99            Error::TimeoutError,
100        ] {
101            assert!(policy.predicate.test(err));
102        }
103        #[allow(clippy::single_element_loop)]
104        for err in &[Error::Other] {
105            assert!(!policy.predicate.test(err));
106        }
107        assert_eq!(policy.max_retries, 5);
108        assert_eq!(policy.backoff, Backoff::default());
109    }
110
111    #[test]
112    fn test_default_retry_non_idempotent() {
113        let policy = default_retry_non_idempotent();
114        for err in &[
115            Error::TooManyRequests {
116                retry_after_delay_seconds: None,
117            },
118            Error::ServiceUnavailable {
119                retry_after_delay_seconds: None,
120            },
121        ] {
122            assert!(policy.predicate.test(err));
123        }
124        for err in &[
125            Error::BadGateway,
126            Error::GatewayTimeout,
127            Error::ConnectionError,
128            Error::TimeoutError,
129            Error::Other,
130        ] {
131            assert!(!policy.predicate.test(err));
132        }
133        assert_eq!(policy.max_retries, 5);
134        assert_eq!(policy.backoff, Backoff::default());
135    }
136
137    #[cfg(feature = "alloc")]
138    #[test]
139    fn test_error_display() {
140        assert_eq!(alloc::format!("{}", Error::BadGateway), "BadGateway")
141    }
142}