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}