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// Note: Macros mq_client_err! and client_broker_err! are now defined in lib.rs
108// to ensure they're available throughout the crate
109
110#[derive(Error, Debug)]
111#[error("{message}")]
112pub struct ClientErr {
113 response_code: i32,
114 error_message: Option<CheetahString>,
115 message: CheetahString,
116}
117
118impl ClientErr {
119 pub fn new(error_message: impl Into<CheetahString>) -> Self {
120 let error_message = error_message.into();
121 let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
122 Self {
123 response_code: -1,
124 error_message: Some(error_message),
125 message: CheetahString::from(message),
126 }
127 }
128
129 pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
130 let error_message = error_message.into();
131 let message = FAQUrl::attach_default_url(Some(
132 format!("CODE: {} DESC: {}", response_code, error_message,).as_str(),
133 ));
134 Self {
135 response_code,
136 error_message: Some(error_message),
137 message: CheetahString::from(message),
138 }
139 }
140
141 pub fn response_code(&self) -> i32 {
142 self.response_code
143 }
144
145 pub fn error_message(&self) -> Option<&CheetahString> {
146 self.error_message.as_ref()
147 }
148}
149
150#[derive(Error, Debug)]
151#[error("{message}")]
152pub struct RequestTimeoutErr {
153 response_code: i32,
154 error_message: Option<CheetahString>,
155 message: CheetahString,
156}
157
158impl RequestTimeoutErr {
159 pub fn new(error_message: impl Into<CheetahString>) -> Self {
160 let error_message = error_message.into();
161 let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
162 Self {
163 response_code: -1,
164 error_message: Some(error_message),
165 message: CheetahString::from(message),
166 }
167 }
168
169 pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
170 let error_message = error_message.into();
171 let message = FAQUrl::attach_default_url(Some(
172 format!("CODE: {} DESC: {}", response_code, error_message,).as_str(),
173 ));
174 Self {
175 response_code,
176 error_message: Some(error_message),
177 message: CheetahString::from(message),
178 }
179 }
180
181 pub fn response_code(&self) -> i32 {
182 self.response_code
183 }
184
185 pub fn error_message(&self) -> Option<&CheetahString> {
186 self.error_message.as_ref()
187 }
188}
189
190#[macro_export]
191macro_rules! request_timeout_err {
192 // Handle errors with a custom ResponseCode and formatted string
193 ($response_code:expr, $fmt:expr, $($arg:expr),*) => {{
194 let formatted_msg = format!($fmt, $($arg),*);
195 std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
196 $crate::client_error::RequestTimeoutErr::new_with_code(
197 $response_code as i32,
198 formatted_msg,
199 ),
200 ))
201 }};
202 ($response_code:expr, $error_message:expr) => {{
203 std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
204 $crate::client_error::RequestTimeoutErr::new_with_code(
205 $response_code as i32,
206 $error_message,
207 ),
208 ))
209 }};
210 // Handle errors without a ResponseCode, using only the error message
211 ($error_message:expr) => {{
212 std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
213 $crate::client_error::RequestTimeoutErr::new($error_message),
214 ))
215 }};
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use crate::client_error;
222
223 #[test]
224 fn client_err_with_response_code_formats_correctly() {
225 let result: std::result::Result<(), client_error::MQClientError> =
226 Err(mq_client_err!(404, "Error: not found"));
227 assert!(result.is_err());
228 if let Err(MQClientError::MQClientErr(err)) = result {
229 assert_eq!(err.response_code(), 404);
230 assert_eq!(err.error_message().unwrap(), "Error: not found");
231 } else {
232 panic!("Expected MQClientError::MQClientErr");
233 }
234 }
235
236 #[test]
237 fn client_broker_err_with_response_code_and_broker_formats_correctly() {
238 let result: std::result::Result<(), client_error::MQClientError> =
239 Err(client_broker_err!(404, "Error: {}", "127.0.0.1"));
240 assert!(result.is_err());
241 if let Err(MQClientError::MQClientBrokerError(err)) = result {
242 assert_eq!(err.response_code(), 404);
243 assert_eq!(err.error_message().unwrap(), "Error: {}");
244 assert_eq!(err.broker_addr().unwrap(), "127.0.0.1");
245 }
246 }
247
248 #[test]
249 fn client_broker_err_with_response_code_formats_correctly() {
250 let result: std::result::Result<(), client_error::MQClientError> =
251 Err(client_broker_err!(404, "Error: not found"));
252 assert!(result.is_err());
253 if let Err(MQClientError::MQClientBrokerError(err)) = result {
254 assert_eq!(err.response_code(), 404);
255 assert_eq!(err.error_message().unwrap(), "Error: not found");
256 assert!(err.broker_addr().is_none());
257 }
258 }
259
260 #[test]
261 fn request_timeout_err_with_response_code_formats_correctly() {
262 let result: std::result::Result<(), client_error::MQClientError> =
263 request_timeout_err!(408, "Request timed out");
264 assert!(result.is_err());
265 if let Err(MQClientError::RequestTimeoutError(err)) = result {
266 assert_eq!(err.response_code(), 408);
267 assert_eq!(err.error_message().unwrap(), "Request timed out");
268 }
269 }
270
271 #[test]
272 fn request_timeout_err_without_response_code_formats_correctly() {
273 let result: Result<(), client_error::MQClientError> = request_timeout_err!("Timeout error");
274 assert!(result.is_err());
275 if let Err(MQClientError::RequestTimeoutError(err)) = result {
276 assert_eq!(err.response_code(), -1);
277 assert_eq!(err.error_message().unwrap(), "Timeout error");
278 }
279 }
280
281 #[test]
282 fn request_timeout_err_with_multiple_arguments_formats_correctly() {
283 let result: Result<(), client_error::MQClientError> =
284 request_timeout_err!(504, "Error: {} - {}", "Gateway", "Timeout");
285 assert!(result.is_err());
286 if let Err(MQClientError::RequestTimeoutError(err)) = result {
287 assert_eq!(err.response_code(), 504);
288 assert_eq!(err.error_message().unwrap(), "Error: Gateway - Timeout");
289 }
290 }
291
292 #[test]
293 fn mq_client_err_with_response_code_formats_correctly() {
294 let result: std::result::Result<(), client_error::MQClientError> =
295 Err(mq_client_err!(404, "Error: {}", "not found"));
296 assert!(result.is_err());
297 if let Err(MQClientError::MQClientErr(err)) = result {
298 assert_eq!(err.response_code(), 404);
299 assert_eq!(err.error_message().unwrap(), "Error: not found");
300 }
301 }
302
303 #[test]
304 fn mq_client_err_without_response_code_formats_correctly() {
305 let result: Result<(), client_error::MQClientError> = Err(mq_client_err!("simple error"));
306 assert!(result.is_err());
307 if let Err(MQClientError::MQClientErr(err)) = result {
308 assert_eq!(err.response_code(), -1);
309 assert_eq!(err.error_message().unwrap(), "simple error");
310 }
311 }
312
313 #[test]
314 fn mq_client_err_with_multiple_arguments_formats_correctly() {
315 let result: Result<(), client_error::MQClientError> =
316 Err(mq_client_err!(500, "Error: {} - {}", "internal", "server error"));
317 assert!(result.is_err());
318 if let Err(MQClientError::MQClientErr(err)) = result {
319 assert_eq!(err.response_code(), 500);
320 assert_eq!(
321 err.error_message().unwrap(),
322 "Error: internal - server error"
323 );
324 }
325 }
326
327 #[test]
328 fn mq_broker_err_new_initializes_correctly() {
329 let error = MQBrokerErr::new(404, "not found");
330 assert_eq!(error.response_code(), 404);
331 assert_eq!(error.error_message().unwrap(), "not found");
332 assert!(error.broker_addr().is_none());
333 }
334
335 #[test]
336 fn mq_broker_err_new_with_broker_initializes_correctly() {
337 let error = MQBrokerErr::new_with_broker(404, "not found", "127.0.0.1");
338 assert_eq!(error.response_code(), 404);
339 assert_eq!(error.error_message().unwrap(), "not found");
340 assert_eq!(error.broker_addr().unwrap(), "127.0.0.1");
341 }
342
343 #[test]
344 fn client_err_new_initializes_correctly() {
345 let error = ClientErr::new("client error");
346 assert_eq!(error.response_code(), -1);
347 assert_eq!(error.error_message().unwrap(), "client error");
348 }
349
350 #[test]
351 fn client_err_new_with_code_initializes_correctly() {
352 let error = ClientErr::new_with_code(500, "internal error");
353 assert_eq!(error.response_code(), 500);
354 assert_eq!(error.error_message().unwrap(), "internal error");
355 }
356
357 #[test]
358 fn request_timeout_err_new_initializes_correctly() {
359 let error = RequestTimeoutErr::new("timeout error");
360 assert_eq!(error.response_code(), -1);
361 assert_eq!(error.error_message().unwrap(), "timeout error");
362 }
363
364 #[test]
365 fn request_timeout_err_new_with_code_initializes_correctly() {
366 let error = RequestTimeoutErr::new_with_code(408, "request timeout");
367 assert_eq!(error.response_code(), 408);
368 assert_eq!(error.error_message().unwrap(), "request timeout");
369 }
370}
371*/