1use thiserror::Error;
6
7#[derive(Error, Debug)]
9pub enum RustRabbitError {
10 #[error("Connection error: {0}")]
11 Connection(String),
12
13 #[error("RabbitMQ protocol error: {0}")]
14 Protocol(#[from] lapin::Error),
15
16 #[error("Serialization error: {0}")]
17 Serialization(String),
18
19 #[error("Configuration error: {0}")]
20 Configuration(String),
21
22 #[error("Consumer error: {0}")]
23 Consumer(String),
24
25 #[error("Publisher error: {0}")]
26 Publisher(String),
27
28 #[error("Retry error: {0}")]
29 Retry(String),
30
31 #[error("IO error: {0}")]
32 Io(#[from] std::io::Error),
33}
34
35pub type Result<T> = std::result::Result<T, RustRabbitError>;
37
38impl RustRabbitError {
39 pub fn is_retryable(&self) -> bool {
41 match self {
42 RustRabbitError::Connection(_) => true,
44 RustRabbitError::Protocol(lapin_error) => {
45 matches!(
47 lapin_error,
48 lapin::Error::IOError(_) | lapin::Error::ProtocolError(_)
49 )
50 }
51 RustRabbitError::Serialization(_) => false,
53 RustRabbitError::Configuration(_) => false,
54 RustRabbitError::Consumer(_) => true,
56 RustRabbitError::Publisher(_) => true,
57 RustRabbitError::Retry(_) => false,
59 RustRabbitError::Io(_) => true,
61 }
62 }
63
64 pub fn is_connection_error(&self) -> bool {
66 matches!(
67 self,
68 RustRabbitError::Connection(_) | RustRabbitError::Protocol(_) | RustRabbitError::Io(_)
69 )
70 }
71
72 pub fn user_message(&self) -> String {
74 match self {
75 RustRabbitError::Connection(_) => {
76 "Failed to connect to RabbitMQ. Please check your connection settings.".to_string()
77 }
78 RustRabbitError::Protocol(_) => {
79 "RabbitMQ protocol error. The connection might be unstable.".to_string()
80 }
81 RustRabbitError::Serialization(_) => {
82 "Failed to serialize/deserialize message. Please check your message format."
83 .to_string()
84 }
85 RustRabbitError::Configuration(_) => {
86 "Configuration error. Please check your settings.".to_string()
87 }
88 RustRabbitError::Consumer(_) => {
89 "Consumer error. Failed to process message.".to_string()
90 }
91 RustRabbitError::Publisher(_) => "Publisher error. Failed to send message.".to_string(),
92 RustRabbitError::Retry(_) => {
93 "Retry mechanism failed. Message processing could not be completed.".to_string()
94 }
95 RustRabbitError::Io(_) => {
96 "IO error occurred. This might be a temporary issue.".to_string()
97 }
98 }
99 }
100}
101
102impl From<serde_json::Error> for RustRabbitError {
104 fn from(err: serde_json::Error) -> Self {
105 RustRabbitError::Serialization(err.to_string())
106 }
107}
108
109impl From<url::ParseError> for RustRabbitError {
111 fn from(err: url::ParseError) -> Self {
112 RustRabbitError::Configuration(format!("Invalid URL: {}", err))
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_error_retryable() {
122 let conn_error = RustRabbitError::Connection("test".to_string());
123 assert!(conn_error.is_retryable());
124
125 let serialization_error = RustRabbitError::Serialization("test".to_string());
126 assert!(!serialization_error.is_retryable());
127
128 let config_error = RustRabbitError::Configuration("test".to_string());
129 assert!(!config_error.is_retryable());
130
131 let retry_error = RustRabbitError::Retry("test".to_string());
132 assert!(!retry_error.is_retryable());
133 }
134
135 #[test]
136 fn test_connection_error_detection() {
137 let conn_error = RustRabbitError::Connection("test".to_string());
138 assert!(conn_error.is_connection_error());
139
140 let serialization_error = RustRabbitError::Serialization("test".to_string());
141 assert!(!serialization_error.is_connection_error());
142 }
143
144 #[test]
145 fn test_user_messages() {
146 let errors = vec![
147 RustRabbitError::Connection("test".to_string()),
148 RustRabbitError::Serialization("test".to_string()),
149 RustRabbitError::Configuration("test".to_string()),
150 ];
151
152 for error in errors {
153 let message = error.user_message();
154 assert!(!message.is_empty());
155 assert!(!message.contains("test")); }
157 }
158
159 #[test]
160 fn test_from_serde_json_error() {
161 let json_error = serde_json::from_str::<i32>("invalid json").unwrap_err();
162 let rabbit_error = RustRabbitError::from(json_error);
163
164 matches!(rabbit_error, RustRabbitError::Serialization(_));
165 }
166}