rocketmq_client_rust/consumer/
pop_callback.rs1use std::future::Future;
16use std::pin::Pin;
17use std::sync::Arc;
18
19use crate::ClientError;
20use rocketmq_model::common::message::message_queue::MessageQueue;
21use rocketmq_model::common::mix_all;
22use rocketmq_protocol::code::response_code::ResponseCode;
23use rocketmq_protocol::protocol::heartbeat::subscription_data::SubscriptionData;
24use tracing::warn;
25
26use crate::consumer::consumer_impl::default_mq_push_consumer_impl::DefaultMQPushConsumerImpl;
27use crate::consumer::consumer_impl::default_mq_push_consumer_impl::PULL_TIME_DELAY_MILLS_WHEN_BROKER_FLOW_CONTROL;
28use crate::consumer::consumer_impl::pop_request::PopRequest;
29use crate::consumer::pop_result::PopResult;
30use crate::consumer::pop_status::PopStatus;
31
32#[trait_variant::make(PopCallback: Send)]
36pub trait PopCallbackInner {
37 async fn on_success(&mut self, pop_result: PopResult);
43
44 fn on_error(&mut self, e: ClientError);
50}
51
52pub type PopCallbackFn = Arc<
80 dyn Fn(Option<PopResult>, Option<ClientError>) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> + Send + Sync,
81>;
82
83fn broker_response_code(error: &ClientError) -> Option<ResponseCode> {
84 error.broker_response_code().map(ResponseCode::from)
85}
86
87pub struct DefaultPopCallback {
88 pub(crate) push_consumer_impl: Arc<DefaultMQPushConsumerImpl>,
89 pub(crate) message_queue_inner: Option<MessageQueue>,
90 pub(crate) subscription_data: Option<SubscriptionData>,
91 pub(crate) pop_request: Option<PopRequest>,
92}
93
94impl PopCallback for DefaultPopCallback {
95 async fn on_success(&mut self, pop_result: PopResult) {
96 let push_consumer_impl = self.push_consumer_impl.clone();
97
98 let Some(message_queue_inner) = self.message_queue_inner.take() else {
99 warn!("pop callback success ignored: message queue is missing");
100 return;
101 };
102 let Some(subscription_data) = self.subscription_data.take() else {
103 warn!(
104 "pop callback success ignored: subscription data is missing, mq={}",
105 message_queue_inner
106 );
107 if let Some(pop_request) = self.pop_request.take() {
108 let delay = push_consumer_impl.pull_time_delay_mills_when_exception;
109 push_consumer_impl.execute_pop_request_later(pop_request, delay);
110 }
111 return;
112 };
113 let Some(pop_request) = self.pop_request.take() else {
114 warn!(
115 "pop callback success ignored: pop request is missing, mq={}",
116 message_queue_inner
117 );
118 return;
119 };
120
121 let pop_result = push_consumer_impl
122 .process_pop_result(pop_result, &subscription_data)
123 .await;
124 match pop_result.pop_status {
125 PopStatus::Found => {
126 if pop_result.msg_found_list.as_ref().is_none_or(|value| value.is_empty()) {
127 push_consumer_impl.execute_pop_request_immediately(pop_request).await;
128 } else {
129 let Some(consume_message_pop_service) = push_consumer_impl.consume_message_pop_service() else {
130 warn!(
131 "pop callback found messages but ConsumeMessagePopService is not initialized, mq={}",
132 message_queue_inner
133 );
134 let delay = push_consumer_impl.pull_time_delay_mills_when_exception;
135 push_consumer_impl.execute_pop_request_later(pop_request, delay);
136 return;
137 };
138 consume_message_pop_service
139 .submit_pop_consume_request(
140 pop_result.msg_found_list.unwrap_or_default(),
141 pop_request.get_pop_process_queue(),
142 pop_request.get_message_queue(),
143 )
144 .await;
145 let pull_interval = push_consumer_impl.consumer_config_snapshot().pull_interval;
146 if pull_interval > 0 {
147 push_consumer_impl.execute_pop_request_later(pop_request, pull_interval);
148 } else {
149 push_consumer_impl.execute_pop_request_immediately(pop_request).await;
150 }
151 }
152 }
153 PopStatus::NoNewMsg | PopStatus::PollingNotFound => {
154 push_consumer_impl.execute_pop_request_immediately(pop_request).await;
155 }
156 PopStatus::PollingFull => {
157 let pull_time_delay_mills_when_exception = push_consumer_impl.pull_time_delay_mills_when_exception;
158 push_consumer_impl.execute_pop_request_later(pop_request, pull_time_delay_mills_when_exception);
159 }
160 }
161 }
162
163 fn on_error(&mut self, err: ClientError) {
164 let push_consumer_impl = self.push_consumer_impl.clone();
165
166 let Some(message_queue_inner) = self.message_queue_inner.take() else {
167 warn!("pop callback exception ignored: message queue is missing, error={err}");
168 return;
169 };
170 let Some(pop_request) = self.pop_request.take() else {
171 warn!(
172 "pop callback exception ignored: pop request is missing, mq={}, error={}",
173 message_queue_inner, err
174 );
175 return;
176 };
177 let topic = message_queue_inner.topic_str();
178 let broker_code = broker_response_code(&err);
179 let consumer_group = push_consumer_impl.consumer_config_snapshot().consumer_group.clone();
180 if !topic.starts_with(mix_all::RETRY_GROUP_TOPIC_PREFIX) {
181 if broker_code == Some(ResponseCode::SubscriptionNotLatest) {
182 warn!("the subscription is not latest, group={}", consumer_group,);
183 } else {
184 warn!("execute the pop request exception, group={}", consumer_group);
185 }
186 }
187 let time_delay = if broker_code == Some(ResponseCode::FlowControl) {
188 PULL_TIME_DELAY_MILLS_WHEN_BROKER_FLOW_CONTROL
189 } else {
190 push_consumer_impl.pull_time_delay_mills_when_exception
191 };
192
193 push_consumer_impl.execute_pop_request_later(pop_request, time_delay);
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use cheetah_string::CheetahString;
200 use rocketmq_model::common::message::message_ext::MessageExt;
201
202 use super::*;
203 use crate::base::client_config::ClientConfig;
204 use crate::consumer::consumer_impl::pop_process_queue::PopProcessQueue;
205 use crate::consumer::default_mq_push_consumer::ConsumerConfig;
206
207 fn message_queue() -> MessageQueue {
208 MessageQueue::from_parts("topic", "broker-a", 0)
209 }
210
211 fn pop_request() -> PopRequest {
212 PopRequest::new(
213 CheetahString::from_static_str("topic"),
214 CheetahString::from_static_str("group"),
215 message_queue(),
216 PopProcessQueue::new(),
217 0,
218 )
219 }
220
221 fn new_callback() -> DefaultPopCallback {
222 let consumer_config = ConsumerConfig::default();
223 let push_consumer_impl = Arc::new(DefaultMQPushConsumerImpl::new(
224 crate::runtime::test_client_runtime("pop-callback-test"),
225 ClientConfig::default(),
226 consumer_config,
227 None,
228 ));
229 push_consumer_impl.initialize_self_reference();
230 DefaultPopCallback {
231 push_consumer_impl,
232 message_queue_inner: None,
233 subscription_data: None,
234 pop_request: None,
235 }
236 }
237
238 #[test]
239 fn broker_response_code_reads_broker_error_without_downcast() {
240 let error = crate::ClientError::broker_operation_failed(
241 "POP_MESSAGE",
242 ResponseCode::SubscriptionNotLatest.to_i32(),
243 "subscription not latest",
244 );
245
246 assert_eq!(broker_response_code(&error), Some(ResponseCode::SubscriptionNotLatest));
247 }
248
249 #[tokio::test]
250 async fn success_without_message_queue_is_ignored_without_panic() {
251 let mut callback = new_callback();
252
253 PopCallback::on_success(&mut callback, PopResult::default()).await;
254 }
255
256 #[tokio::test]
257 async fn success_without_subscription_data_is_delayed_without_panic() {
258 let mut callback = new_callback();
259 callback.message_queue_inner = Some(message_queue());
260 callback.pop_request = Some(pop_request());
261
262 PopCallback::on_success(&mut callback, PopResult::default()).await;
263 }
264
265 #[tokio::test]
266 async fn success_without_pop_request_is_ignored_without_panic() {
267 let mut callback = new_callback();
268 callback.message_queue_inner = Some(message_queue());
269 callback.subscription_data = Some(SubscriptionData::default());
270
271 PopCallback::on_success(&mut callback, PopResult::default()).await;
272 }
273
274 #[tokio::test]
275 async fn found_messages_without_pop_service_are_delayed_without_panic() {
276 let mut callback = new_callback();
277 callback.message_queue_inner = Some(message_queue());
278 callback.subscription_data = Some(SubscriptionData::default());
279 callback.pop_request = Some(pop_request());
280 let pop_result = PopResult {
281 msg_found_list: Some(vec![MessageExt::default()]),
282 pop_status: PopStatus::Found,
283 ..Default::default()
284 };
285
286 PopCallback::on_success(&mut callback, pop_result).await;
287 }
288
289 #[test]
290 fn error_without_message_queue_is_ignored_without_panic() {
291 let mut callback = new_callback();
292
293 PopCallback::on_error(&mut callback, ClientError::illegal_argument("test error"));
294 }
295
296 #[test]
297 fn error_without_pop_request_is_ignored_without_panic() {
298 let mut callback = new_callback();
299 callback.message_queue_inner = Some(message_queue());
300
301 PopCallback::on_error(&mut callback, ClientError::illegal_argument("test error"));
302 }
303}