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 use lapin::ErrorKind;
48 matches!(
49 lapin_error.kind(),
50 ErrorKind::IOError(_) | ErrorKind::ProtocolError(_)
51 )
52 }
53 RustRabbitError::Serialization(_) => false,
55 RustRabbitError::Configuration(_) => false,
56 RustRabbitError::Consumer(_) => true,
58 RustRabbitError::Publisher(_) => true,
59 RustRabbitError::Retry(_) => false,
61 RustRabbitError::Io(_) => true,
63 }
64 }
65
66 pub fn is_connection_error(&self) -> bool {
68 matches!(
69 self,
70 RustRabbitError::Connection(_) | RustRabbitError::Protocol(_) | RustRabbitError::Io(_)
71 )
72 }
73
74 pub fn user_message(&self) -> String {
76 match self {
77 RustRabbitError::Connection(_) => {
78 "Failed to connect to RabbitMQ. Please check your connection settings.".to_string()
79 }
80 RustRabbitError::Protocol(_) => {
81 "RabbitMQ protocol error. The connection might be unstable.".to_string()
82 }
83 RustRabbitError::Serialization(_) => {
84 "Failed to serialize/deserialize message. Please check your message format."
85 .to_string()
86 }
87 RustRabbitError::Configuration(_) => {
88 "Configuration error. Please check your settings.".to_string()
89 }
90 RustRabbitError::Consumer(_) => {
91 "Consumer error. Failed to process message.".to_string()
92 }
93 RustRabbitError::Publisher(_) => "Publisher error. Failed to send message.".to_string(),
94 RustRabbitError::Retry(_) => {
95 "Retry mechanism failed. Message processing could not be completed.".to_string()
96 }
97 RustRabbitError::Io(_) => {
98 "IO error occurred. This might be a temporary issue.".to_string()
99 }
100 }
101 }
102}
103
104impl From<serde_json::Error> for RustRabbitError {
106 fn from(err: serde_json::Error) -> Self {
107 RustRabbitError::Serialization(err.to_string())
108 }
109}
110
111impl From<url::ParseError> for RustRabbitError {
113 fn from(err: url::ParseError) -> Self {
114 RustRabbitError::Configuration(format!("Invalid URL: {}", err))
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_error_retryable() {
124 let conn_error = RustRabbitError::Connection("test".to_string());
125 assert!(conn_error.is_retryable());
126
127 let serialization_error = RustRabbitError::Serialization("test".to_string());
128 assert!(!serialization_error.is_retryable());
129
130 let config_error = RustRabbitError::Configuration("test".to_string());
131 assert!(!config_error.is_retryable());
132
133 let retry_error = RustRabbitError::Retry("test".to_string());
134 assert!(!retry_error.is_retryable());
135 }
136
137 #[test]
138 fn test_connection_error_detection() {
139 let conn_error = RustRabbitError::Connection("test".to_string());
140 assert!(conn_error.is_connection_error());
141
142 let serialization_error = RustRabbitError::Serialization("test".to_string());
143 assert!(!serialization_error.is_connection_error());
144 }
145
146 #[test]
147 fn test_user_messages() {
148 let errors = vec![
149 RustRabbitError::Connection("test".to_string()),
150 RustRabbitError::Serialization("test".to_string()),
151 RustRabbitError::Configuration("test".to_string()),
152 ];
153
154 for error in errors {
155 let message = error.user_message();
156 assert!(!message.is_empty());
157 assert!(!message.contains("test")); }
159 }
160
161 #[test]
162 fn test_from_serde_json_error() {
163 let json_error = serde_json::from_str::<i32>("invalid json").unwrap_err();
164 let rabbit_error = RustRabbitError::from(json_error);
165
166 matches!(rabbit_error, RustRabbitError::Serialization(_));
167 }
168}