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