rocketmq_client_rust/client_error.rs
1/*
2// Copyright 2023 The RocketMQ Rust Authors
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use cheetah_string::CheetahString;
17use rocketmq_common::common::FAQUrl;
18use rocketmq_remoting::remoting_error::RemotingError;
19use thiserror::Error;
20
21#[derive(Debug, Error)]
22pub enum MQClientError {
23 #[error("{0}")]
24 MQClientErr(#[from] ClientErr),
25
26 #[error("{0}")]
27 RemotingTooMuchRequestError(String),
28
29 #[error("{0}")]
30 MQClientBrokerError(#[from] MQBrokerErr),
31
32 #[error("{0}")]
33 RequestTimeoutError(#[from] RequestTimeoutErr),
34
35 #[error("Client exception occurred: CODE:{0}, broker address:{1}, Message:{2}")]
36 OffsetNotFoundError(i32, String, String),
37
38 #[error("{0}")]
39 RemotingError(#[from] RemotingError),
40
41 #[error("{0}")]
42 IllegalArgumentError(String),
43
44 #[error("{0}")]
45 CommonError(#[from] rocketmq_common::error::Error),
46}
47
48#[derive(Error, Debug)]
49#[error("{message}")]
50pub struct MQBrokerErr {
51 response_code: i32,
52 error_message: Option<CheetahString>,
53 broker_addr: Option<CheetahString>,
54 message: CheetahString,
55}
56
57impl MQBrokerErr {
58 pub fn new(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
59 let error_message = error_message.into();
60 let message = FAQUrl::attach_default_url(Some(
61 format!("CODE: {} DESC: {}", response_code, error_message,).as_str(),
62 ));
63 Self {
64 response_code,
65 error_message: Some(error_message),
66 broker_addr: None,
67 message: CheetahString::from(message),
68 }
69 }
70
71 pub fn new_with_broker(
72 response_code: i32,
73 error_message: impl Into<CheetahString>,
74 broker_addr: impl Into<CheetahString>,
75 ) -> Self {
76 let broker_addr = broker_addr.into();
77 let error_message = error_message.into();
78 let message = FAQUrl::attach_default_url(Some(
79 format!(
80 "CODE: {} DESC: {} BROKER: {}",
81 response_code, error_message, broker_addr
82 )
83 .as_str(),
84 ));
85 Self {
86 response_code,
87 error_message: Some(error_message),
88 broker_addr: Some(broker_addr),
89 message: CheetahString::from(message),
90 }
91 }
92
93 pub fn response_code(&self) -> i32 {
94 self.response_code
95 }
96
97 pub fn error_message(&self) -> Option<&CheetahString> {
98 self.error_message.as_ref()
99 }
100
101 pub fn broker_addr(&self) -> Option<&CheetahString> {
102 self.broker_addr.as_ref()
103 }
104}
105
106// Note: Macros mq_client_err! and client_broker_err! are now defined in lib.rs
107// to ensure they're available throughout the crate
108
109#[derive(Error, Debug)]
110#[error("{message}")]
111pub struct ClientErr {
112 response_code: i32,
113 error_message: Option<CheetahString>,
114 message: CheetahString,
115}
116
117impl ClientErr {
118 pub fn new(error_message: impl Into<CheetahString>) -> Self {
119 let error_message = error_message.into();
120 let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
121 Self {
122 response_code: -1,
123 error_message: Some(error_message),
124 message: CheetahString::from(message),
125 }
126 }
127
128 pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
129 let error_message = error_message.into();
130 let message = FAQUrl::attach_default_url(Some(
131 format!("CODE: {} DESC: {}", response_code, error_message,).as_str(),
132 ));
133 Self {
134 response_code,
135 error_message: Some(error_message),
136 message: CheetahString::from(message),
137 }
138 }
139
140 pub fn response_code(&self) -> i32 {
141 self.response_code
142 }
143
144 pub fn error_message(&self) -> Option<&CheetahString> {
145 self.error_message.as_ref()
146 }
147}
148
149#[derive(Error, Debug)]
150#[error("{message}")]
151pub struct RequestTimeoutErr {
152 response_code: i32,
153 error_message: Option<CheetahString>,
154 message: CheetahString,
155}
156
157impl RequestTimeoutErr {
158 pub fn new(error_message: impl Into<CheetahString>) -> Self {
159 let error_message = error_message.into();
160 let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
161 Self {
162 response_code: -1,
163 error_message: Some(error_message),
164 message: CheetahString::from(message),
165 }
166 }
167
168 pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
169 let error_message = error_message.into();
170 let message = FAQUrl::attach_default_url(Some(
171 format!("CODE: {} DESC: {}", response_code, error_message,).as_str(),
172 ));
173 Self {
174 response_code,
175 error_message: Some(error_message),
176 message: CheetahString::from(message),
177 }
178 }
179
180 pub fn response_code(&self) -> i32 {
181 self.response_code
182 }
183
184 pub fn error_message(&self) -> Option<&CheetahString> {
185 self.error_message.as_ref()
186 }
187}
188
189#[macro_export]
190macro_rules! request_timeout_err {
191 // Handle errors with a custom ResponseCode and formatted string
192 ($response_code:expr, $fmt:expr, $($arg:expr),*) => {{
193 let formatted_msg = format!($fmt, $($arg),*);
194 std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
195 $crate::client_error::RequestTimeoutErr::new_with_code(
196 $response_code as i32,
197 formatted_msg,
198 ),
199 ))
200 }};
201 ($response_code:expr, $error_message:expr) => {{
202 std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
203 $crate::client_error::RequestTimeoutErr::new_with_code(
204 $response_code as i32,
205 $error_message,
206 ),
207 ))
208 }};
209 // Handle errors without a ResponseCode, using only the error message
210 ($error_message:expr) => {{
211 std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
212 $crate::client_error::RequestTimeoutErr::new($error_message),
213 ))
214 }};
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220 use crate::client_error;
221
222 #[test]
223 fn client_err_with_response_code_formats_correctly() {
224 let result: std::result::Result<(), client_error::MQClientError> =
225 Err(mq_client_err!(404, "Error: not found"));
226 assert!(result.is_err());
227 if let Err(MQClientError::MQClientErr(err)) = result {
228 assert_eq!(err.response_code(), 404);
229 assert_eq!(err.error_message().unwrap(), "Error: not found");
230 } else {
231 panic!("Expected MQClientError::MQClientErr");
232 }
233 }
234
235 #[test]
236 fn client_broker_err_with_response_code_and_broker_formats_correctly() {
237 let result: std::result::Result<(), client_error::MQClientError> =
238 Err(client_broker_err!(404, "Error: {}", "127.0.0.1"));
239 assert!(result.is_err());
240 if let Err(MQClientError::MQClientBrokerError(err)) = result {
241 assert_eq!(err.response_code(), 404);
242 assert_eq!(err.error_message().unwrap(), "Error: {}");
243 assert_eq!(err.broker_addr().unwrap(), "127.0.0.1");
244 }
245 }
246
247 #[test]
248 fn client_broker_err_with_response_code_formats_correctly() {
249 let result: std::result::Result<(), client_error::MQClientError> =
250 Err(client_broker_err!(404, "Error: not found"));
251 assert!(result.is_err());
252 if let Err(MQClientError::MQClientBrokerError(err)) = result {
253 assert_eq!(err.response_code(), 404);
254 assert_eq!(err.error_message().unwrap(), "Error: not found");
255 assert!(err.broker_addr().is_none());
256 }
257 }
258
259 #[test]
260 fn request_timeout_err_with_response_code_formats_correctly() {
261 let result: std::result::Result<(), client_error::MQClientError> =
262 request_timeout_err!(408, "Request timed out");
263 assert!(result.is_err());
264 if let Err(MQClientError::RequestTimeoutError(err)) = result {
265 assert_eq!(err.response_code(), 408);
266 assert_eq!(err.error_message().unwrap(), "Request timed out");
267 }
268 }
269
270 #[test]
271 fn request_timeout_err_without_response_code_formats_correctly() {
272 let result: Result<(), client_error::MQClientError> = request_timeout_err!("Timeout error");
273 assert!(result.is_err());
274 if let Err(MQClientError::RequestTimeoutError(err)) = result {
275 assert_eq!(err.response_code(), -1);
276 assert_eq!(err.error_message().unwrap(), "Timeout error");
277 }
278 }
279
280 #[test]
281 fn request_timeout_err_with_multiple_arguments_formats_correctly() {
282 let result: Result<(), client_error::MQClientError> =
283 request_timeout_err!(504, "Error: {} - {}", "Gateway", "Timeout");
284 assert!(result.is_err());
285 if let Err(MQClientError::RequestTimeoutError(err)) = result {
286 assert_eq!(err.response_code(), 504);
287 assert_eq!(err.error_message().unwrap(), "Error: Gateway - Timeout");
288 }
289 }
290
291 #[test]
292 fn mq_client_err_with_response_code_formats_correctly() {
293 let result: std::result::Result<(), client_error::MQClientError> =
294 Err(mq_client_err!(404, "Error: {}", "not found"));
295 assert!(result.is_err());
296 if let Err(MQClientError::MQClientErr(err)) = result {
297 assert_eq!(err.response_code(), 404);
298 assert_eq!(err.error_message().unwrap(), "Error: not found");
299 }
300 }
301
302 #[test]
303 fn mq_client_err_without_response_code_formats_correctly() {
304 let result: Result<(), client_error::MQClientError> = Err(mq_client_err!("simple error"));
305 assert!(result.is_err());
306 if let Err(MQClientError::MQClientErr(err)) = result {
307 assert_eq!(err.response_code(), -1);
308 assert_eq!(err.error_message().unwrap(), "simple error");
309 }
310 }
311
312 #[test]
313 fn mq_client_err_with_multiple_arguments_formats_correctly() {
314 let result: Result<(), client_error::MQClientError> =
315 Err(mq_client_err!(500, "Error: {} - {}", "internal", "server error"));
316 assert!(result.is_err());
317 if let Err(MQClientError::MQClientErr(err)) = result {
318 assert_eq!(err.response_code(), 500);
319 assert_eq!(
320 err.error_message().unwrap(),
321 "Error: internal - server error"
322 );
323 }
324 }
325
326 #[test]
327 fn mq_broker_err_new_initializes_correctly() {
328 let error = MQBrokerErr::new(404, "not found");
329 assert_eq!(error.response_code(), 404);
330 assert_eq!(error.error_message().unwrap(), "not found");
331 assert!(error.broker_addr().is_none());
332 }
333
334 #[test]
335 fn mq_broker_err_new_with_broker_initializes_correctly() {
336 let error = MQBrokerErr::new_with_broker(404, "not found", "127.0.0.1");
337 assert_eq!(error.response_code(), 404);
338 assert_eq!(error.error_message().unwrap(), "not found");
339 assert_eq!(error.broker_addr().unwrap(), "127.0.0.1");
340 }
341
342 #[test]
343 fn client_err_new_initializes_correctly() {
344 let error = ClientErr::new("client error");
345 assert_eq!(error.response_code(), -1);
346 assert_eq!(error.error_message().unwrap(), "client error");
347 }
348
349 #[test]
350 fn client_err_new_with_code_initializes_correctly() {
351 let error = ClientErr::new_with_code(500, "internal error");
352 assert_eq!(error.response_code(), 500);
353 assert_eq!(error.error_message().unwrap(), "internal error");
354 }
355
356 #[test]
357 fn request_timeout_err_new_initializes_correctly() {
358 let error = RequestTimeoutErr::new("timeout error");
359 assert_eq!(error.response_code(), -1);
360 assert_eq!(error.error_message().unwrap(), "timeout error");
361 }
362
363 #[test]
364 fn request_timeout_err_new_with_code_initializes_correctly() {
365 let error = RequestTimeoutErr::new_with_code(408, "request timeout");
366 assert_eq!(error.response_code(), 408);
367 assert_eq!(error.error_message().unwrap(), "request timeout");
368 }
369}
370*/