grid_sdk/error/
unavailable.rs

1// Copyright 2018-2020 Cargill Incorporated
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Module containing ResourceTemporarilyUnavailableError implementation.
16
17use std::error;
18use std::fmt;
19use std::time::Duration;
20
21/// An error which is returned when an underlying resource is unavailable.
22///
23/// This error can be handled by retrying, usually in a loop with a small delay.
24#[derive(Debug)]
25pub struct ResourceTemporarilyUnavailableError {
26    source: Box<dyn error::Error>,
27    retry_duration_hint: Option<Duration>,
28}
29
30impl ResourceTemporarilyUnavailableError {
31    /// Constructs a new `ResourceTemporarilyUnavailableError` from a specified source error.
32    ///
33    /// The implementation of `std::fmt::Display` for this error will simply pass through the
34    /// display of the source message unmodified.
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use grid_sdk::error::ResourceTemporarilyUnavailableError;
40    ///
41    /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "io error");
42    /// let rtu_error = ResourceTemporarilyUnavailableError::from_source(Box::new(io_err));
43    /// assert_eq!(format!("{}", rtu_error), "io error");
44    /// ```
45    pub fn from_source(source: Box<dyn error::Error>) -> Self {
46        Self {
47            source,
48            retry_duration_hint: None,
49        }
50    }
51
52    /// Constructs a new `ResourceTemporarilyUnavailableError` from a specified source error with
53    /// a retry duration hint.
54    ///
55    /// The hint specified here can be used by the caller as the duration between retry attempts.
56    /// Callers may ignore this hint and provide their own algorithms, or may use this `Duration`
57    /// as provided.
58    ///
59    /// The implementation of `std::fmt::Display` for this error will simply pass through the
60    /// display of the source message unmodified.
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// use std::time::Duration;
66    ///
67    /// use grid_sdk::error::ResourceTemporarilyUnavailableError;
68    ///
69    /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "io error");
70    /// let rtu_error = ResourceTemporarilyUnavailableError::from_source_with_hint(Box::new(io_err), Duration::new(10, 0));
71    /// assert_eq!(format!("{}", rtu_error), "io error");
72    /// ```
73    pub fn from_source_with_hint(
74        source: Box<dyn error::Error>,
75        retry_duration_hint: Duration,
76    ) -> Self {
77        Self {
78            source,
79            retry_duration_hint: Some(retry_duration_hint),
80        }
81    }
82
83    /// Returns the duration which the underlying library provides as a suggestion for an
84    /// appropriate amount of time between retry attempts.
85    pub fn retry_duration_hint(&self) -> Option<Duration> {
86        self.retry_duration_hint
87    }
88}
89
90impl error::Error for ResourceTemporarilyUnavailableError {
91    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
92        Some(self.source.as_ref())
93    }
94}
95
96impl fmt::Display for ResourceTemporarilyUnavailableError {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        write!(f, "{}", self.source)
99    }
100}
101
102#[cfg(test)]
103pub mod tests {
104    use std::time::Duration;
105
106    use crate::error::InternalError;
107
108    use super::*;
109
110    /// Tests that error constructed with `ResourceTemporarilyUnavailableError::from_source` return
111    /// a display string which is the same as the source's display string.
112    #[test]
113    fn test_display_from_source() {
114        let msg = "test message";
115        let err = ResourceTemporarilyUnavailableError::from_source(Box::new(
116            InternalError::with_message(msg.to_string()),
117        ));
118        assert_eq!(format!("{}", err), msg);
119    }
120
121    /// Tests that error constructed with
122    /// `ResourceTemporarilyUnavailableError::from_source_with_hint` return a display string which
123    /// is the same as the source's display string.
124    #[test]
125    fn test_display_from_source_with_hint() {
126        let msg = "test message";
127        let err = ResourceTemporarilyUnavailableError::from_source_with_hint(
128            Box::new(InternalError::with_message(msg.to_string())),
129            Duration::new(10, 0),
130        );
131        assert_eq!(format!("{}", err), msg);
132    }
133}