1use std::collections::HashMap;
16use std::sync::Arc;
17
18use arc_swap::ArcSwap;
19use cheetah_string::CheetahString;
20use rocketmq_model::common::consumer::consume_from_where::ConsumeFromWhere;
21use rocketmq_model::common::message::message_ext::MessageExt;
22use rocketmq_model::common::message::message_queue::MessageQueue;
23use rocketmq_protocol::common::message::message_decoder as MessageDecoder;
24use rocketmq_protocol::protocol::body::consumer_running_info::ConsumerRunningInfo;
25use rocketmq_protocol::protocol::heartbeat::message_model::MessageModel;
26use rocketmq_protocol::protocol::namespace_util::NamespaceUtil;
27use rocketmq_runtime::common::time_utils;
28use rocketmq_runtime::common::time_utils::current_millis;
29use rocketmq_transport::api::RPCHook;
30
31use crate::base::client_config::ClientConfig;
32use crate::base::client_options::ClientOptions;
33use crate::base::query_result::QueryResult;
34use crate::consumer::allocate_message_queue_strategy::AllocateMessageQueueStrategy;
35use crate::consumer::consumer_impl::default_mq_push_consumer_impl::DefaultMQPushConsumerImpl;
36use crate::consumer::default_mq_push_consumer_builder::DefaultMQPushConsumerBuilder;
37use crate::consumer::listener::message_listener::MessageListener;
38use crate::consumer::listener::message_listener_concurrently::MessageListenerConcurrently;
39use crate::consumer::listener::message_listener_orderly::MessageListenerOrderly;
40use crate::consumer::message_queue_listener::ArcMessageQueueListener;
41use crate::consumer::message_selector::MessageSelector;
42use crate::consumer::mq_consumer::MQConsumer;
43use crate::consumer::mq_consumer_inner::MQConsumerInner;
44use crate::consumer::mq_push_consumer::MQPushConsumer;
45use crate::consumer::rebalance_strategy::allocate_message_queue_averagely::AllocateMessageQueueAveragely;
46use crate::consumer::store::offset_store::OffsetStore;
47use crate::hook::consume_message_hook::ConsumeMessageHook;
48use crate::runtime::ClientRuntime;
49use crate::trace::async_trace_dispatcher::AsyncTraceDispatcher;
50use crate::trace::hook::consume_message_trace_hook_impl::ConsumeMessageTraceHookImpl;
51use crate::trace::trace_dispatcher::ArcTraceDispatcher;
52use crate::trace::trace_dispatcher::Type;
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum ConsumerTuningProfile {
56 LowLatency,
57 Throughput,
58 LargeMessage,
59 SlowListener,
60}
61
62#[derive(Clone)]
63pub struct ConsumerConfig {
64 pub(crate) consumer_group: CheetahString,
65 pub(crate) topic: CheetahString,
66 pub(crate) sub_expression: CheetahString,
67 pub(crate) message_model: MessageModel,
68 pub(crate) consume_from_where: ConsumeFromWhere,
69 pub(crate) consume_timestamp: Option<CheetahString>,
70 pub(crate) allocate_message_queue_strategy: Option<Arc<dyn AllocateMessageQueueStrategy>>,
71 pub(crate) subscription: Arc<HashMap<CheetahString, CheetahString>>,
73 pub(crate) message_listener: Option<Arc<MessageListener>>,
74 pub(crate) message_queue_listener: Option<ArcMessageQueueListener>,
75 pub(crate) offset_store: Option<Arc<OffsetStore>>,
76 pub(crate) consume_thread_min: u32,
77 pub(crate) consume_thread_max: u32,
78 pub(crate) adjust_thread_pool_nums_threshold: u64,
79 pub(crate) consume_concurrently_max_span: u32,
80 pub(crate) pull_threshold_for_queue: u32,
81 pub(crate) pop_threshold_for_queue: u32,
82 pub(crate) pull_threshold_size_for_queue: u32,
83 pub(crate) pull_threshold_for_topic: i32,
84 pub(crate) pull_threshold_size_for_topic: i32,
85 pub(crate) pull_interval: u64,
86 pub(crate) consume_message_batch_max_size: u32,
87 pub(crate) pull_batch_size: u32,
88 pub(crate) pull_batch_size_in_bytes: u32,
89 pub(crate) post_subscription_when_pull: bool,
90 pub(crate) unit_mode: bool,
91 pub(crate) max_reconsume_times: i32,
92 pub(crate) suspend_current_queue_time_millis: u64,
93 pub(crate) consume_timeout: u64,
94 pub(crate) pop_invisible_time: u64,
95 pub(crate) pop_batch_nums: u32,
96 pub(crate) await_termination_millis_when_shutdown: u64,
97 pub(crate) trace_dispatcher: Option<ArcTraceDispatcher>,
98 pub(crate) client_rebalance: bool,
99 pub(crate) rpc_hook: Option<Arc<dyn RPCHook>>,
100}
101
102impl ConsumerConfig {
103 pub fn consumer_group(&self) -> &CheetahString {
104 &self.consumer_group
105 }
106
107 pub fn message_model(&self) -> MessageModel {
108 self.message_model
109 }
110
111 pub fn consume_from_where(&self) -> ConsumeFromWhere {
112 self.consume_from_where
113 }
114
115 pub fn consume_timestamp(&self) -> &Option<CheetahString> {
116 &self.consume_timestamp
117 }
118
119 pub fn allocate_message_queue_strategy(&self) -> Option<Arc<dyn AllocateMessageQueueStrategy>> {
120 self.allocate_message_queue_strategy.clone()
121 }
122
123 pub fn subscription(&self) -> Arc<HashMap<CheetahString, CheetahString>> {
124 self.subscription.clone()
125 }
126
127 pub fn offset_store(&self) -> Option<Arc<OffsetStore>> {
136 self.offset_store.clone()
137 }
138
139 pub fn consume_thread_min(&self) -> u32 {
140 self.consume_thread_min
141 }
142
143 pub fn consume_thread_max(&self) -> u32 {
144 self.consume_thread_max
145 }
146
147 pub fn adjust_thread_pool_nums_threshold(&self) -> u64 {
148 self.adjust_thread_pool_nums_threshold
149 }
150
151 pub fn consume_concurrently_max_span(&self) -> u32 {
152 self.consume_concurrently_max_span
153 }
154
155 pub fn pull_threshold_for_queue(&self) -> u32 {
156 self.pull_threshold_for_queue
157 }
158
159 pub fn pop_threshold_for_queue(&self) -> u32 {
160 self.pop_threshold_for_queue
161 }
162
163 pub fn pull_threshold_size_for_queue(&self) -> u32 {
164 self.pull_threshold_size_for_queue
165 }
166
167 pub fn pull_threshold_for_topic(&self) -> i32 {
168 self.pull_threshold_for_topic
169 }
170
171 pub fn pull_threshold_size_for_topic(&self) -> i32 {
172 self.pull_threshold_size_for_topic
173 }
174
175 pub fn pull_interval(&self) -> u64 {
176 self.pull_interval
177 }
178
179 pub fn consume_message_batch_max_size(&self) -> u32 {
180 self.consume_message_batch_max_size
181 }
182
183 pub fn pull_batch_size(&self) -> u32 {
184 self.pull_batch_size
185 }
186
187 pub fn pull_batch_size_in_bytes(&self) -> u32 {
188 self.pull_batch_size_in_bytes
189 }
190
191 pub fn post_subscription_when_pull(&self) -> bool {
192 self.post_subscription_when_pull
193 }
194
195 pub fn unit_mode(&self) -> bool {
196 self.unit_mode
197 }
198
199 pub fn max_reconsume_times(&self) -> i32 {
200 self.max_reconsume_times
201 }
202
203 pub fn suspend_current_queue_time_millis(&self) -> u64 {
204 self.suspend_current_queue_time_millis
205 }
206
207 pub fn consume_timeout(&self) -> u64 {
208 self.consume_timeout
209 }
210
211 pub fn pop_invisible_time(&self) -> u64 {
212 self.pop_invisible_time
213 }
214
215 pub fn pop_batch_nums(&self) -> u32 {
216 self.pop_batch_nums
217 }
218
219 pub fn await_termination_millis_when_shutdown(&self) -> u64 {
220 self.await_termination_millis_when_shutdown
221 }
222
223 pub fn trace_dispatcher(&self) -> &Option<ArcTraceDispatcher> {
224 &self.trace_dispatcher
225 }
226
227 pub fn client_rebalance(&self) -> bool {
228 self.client_rebalance
229 }
230
231 pub fn rpc_hook(&self) -> &Option<Arc<dyn RPCHook>> {
232 &self.rpc_hook
233 }
234
235 pub fn apply_tuning_profile(&mut self, profile: ConsumerTuningProfile) {
236 match profile {
237 ConsumerTuningProfile::LowLatency => {
238 self.consume_message_batch_max_size = 1;
239 self.pull_batch_size = 16;
240 self.pull_batch_size_in_bytes = 256 * 1024;
241 self.pull_threshold_for_queue = 256;
242 self.pull_threshold_size_for_queue = 32;
243 self.pull_interval = 0;
244 }
245 ConsumerTuningProfile::Throughput => {
246 self.consume_message_batch_max_size = 16;
247 self.pull_batch_size = 128;
248 self.pull_batch_size_in_bytes = 1024 * 1024;
249 self.pull_threshold_for_queue = 4096;
250 self.pull_threshold_size_for_queue = 256;
251 self.pull_interval = 0;
252 }
253 ConsumerTuningProfile::LargeMessage => {
254 self.consume_message_batch_max_size = 1;
255 self.pull_batch_size = 8;
256 self.pull_batch_size_in_bytes = 512 * 1024;
257 self.pull_threshold_for_queue = 128;
258 self.pull_threshold_size_for_queue = 64;
259 self.pull_interval = 0;
260 }
261 ConsumerTuningProfile::SlowListener => {
262 self.consume_message_batch_max_size = 1;
263 self.pull_batch_size = 16;
264 self.pull_batch_size_in_bytes = 256 * 1024;
265 self.pull_threshold_for_queue = 100;
266 self.pull_threshold_size_for_queue = 16;
267 self.pull_interval = 50;
268 }
269 }
270 }
271
272 pub fn set_consumer_group(&mut self, consumer_group: CheetahString) {
273 self.consumer_group = consumer_group;
274 }
275
276 pub fn set_message_model(&mut self, message_model: MessageModel) {
277 self.message_model = message_model;
278 }
279
280 pub fn set_consume_from_where(&mut self, consume_from_where: ConsumeFromWhere) {
281 self.consume_from_where = consume_from_where;
282 }
283
284 pub fn set_consume_timestamp(&mut self, consume_timestamp: Option<CheetahString>) {
285 self.consume_timestamp = consume_timestamp;
286 }
287
288 pub fn set_allocate_message_queue_strategy(
289 &mut self,
290 allocate_message_queue_strategy: Arc<dyn AllocateMessageQueueStrategy>,
291 ) {
292 self.allocate_message_queue_strategy = Some(allocate_message_queue_strategy);
293 }
294
295 pub fn set_subscription(&mut self, subscription: Arc<HashMap<CheetahString, CheetahString>>) {
300 self.subscription = subscription;
301 }
302
303 pub fn set_message_queue_listener(&mut self, message_queue_listener: Option<ArcMessageQueueListener>) {
311 self.message_queue_listener = message_queue_listener;
312 }
313
314 pub fn set_offset_store(&mut self, offset_store: Option<Arc<OffsetStore>>) {
315 self.offset_store = offset_store;
316 }
317
318 pub fn set_consume_thread_min(&mut self, consume_thread_min: u32) {
319 self.consume_thread_min = consume_thread_min;
320 }
321
322 pub fn set_consume_thread_max(&mut self, consume_thread_max: u32) {
323 self.consume_thread_max = consume_thread_max;
324 }
325
326 pub fn set_adjust_thread_pool_nums_threshold(&mut self, adjust_thread_pool_nums_threshold: u64) {
327 self.adjust_thread_pool_nums_threshold = adjust_thread_pool_nums_threshold;
328 }
329
330 pub fn set_consume_concurrently_max_span(&mut self, consume_concurrently_max_span: u32) {
331 self.consume_concurrently_max_span = consume_concurrently_max_span;
332 }
333
334 pub fn set_pull_threshold_for_queue(&mut self, pull_threshold_for_queue: u32) {
335 self.pull_threshold_for_queue = pull_threshold_for_queue;
336 }
337
338 pub fn set_pop_threshold_for_queue(&mut self, pop_threshold_for_queue: u32) {
339 self.pop_threshold_for_queue = pop_threshold_for_queue;
340 }
341
342 pub fn set_pull_threshold_size_for_queue(&mut self, pull_threshold_size_for_queue: u32) {
343 self.pull_threshold_size_for_queue = pull_threshold_size_for_queue;
344 }
345
346 pub fn set_pull_threshold_for_topic(&mut self, pull_threshold_for_topic: i32) {
347 self.pull_threshold_for_topic = pull_threshold_for_topic;
348 }
349
350 pub fn set_pull_threshold_size_for_topic(&mut self, pull_threshold_size_for_topic: i32) {
351 self.pull_threshold_size_for_topic = pull_threshold_size_for_topic;
352 }
353
354 pub fn set_pull_interval(&mut self, pull_interval: u64) {
355 self.pull_interval = pull_interval;
356 }
357
358 pub fn set_consume_message_batch_max_size(&mut self, consume_message_batch_max_size: u32) {
359 self.consume_message_batch_max_size = consume_message_batch_max_size;
360 }
361
362 pub fn set_pull_batch_size(&mut self, pull_batch_size: u32) {
363 self.pull_batch_size = pull_batch_size;
364 }
365
366 pub fn set_pull_batch_size_in_bytes(&mut self, pull_batch_size_in_bytes: u32) {
367 self.pull_batch_size_in_bytes = pull_batch_size_in_bytes;
368 }
369
370 pub fn set_post_subscription_when_pull(&mut self, post_subscription_when_pull: bool) {
371 self.post_subscription_when_pull = post_subscription_when_pull;
372 }
373
374 pub fn set_unit_mode(&mut self, unit_mode: bool) {
375 self.unit_mode = unit_mode;
376 }
377
378 pub fn set_max_reconsume_times(&mut self, max_reconsume_times: i32) {
379 self.max_reconsume_times = max_reconsume_times;
380 }
381
382 pub fn set_suspend_current_queue_time_millis(&mut self, suspend_current_queue_time_millis: u64) {
383 self.suspend_current_queue_time_millis = suspend_current_queue_time_millis;
384 }
385
386 pub fn set_consume_timeout(&mut self, consume_timeout: u64) {
387 self.consume_timeout = consume_timeout;
388 }
389
390 pub fn set_pop_invisible_time(&mut self, pop_invisible_time: u64) {
391 self.pop_invisible_time = pop_invisible_time;
392 }
393
394 pub fn set_pop_batch_nums(&mut self, pop_batch_nums: u32) {
395 self.pop_batch_nums = pop_batch_nums;
396 }
397
398 pub fn set_await_termination_millis_when_shutdown(&mut self, await_termination_millis_when_shutdown: u64) {
399 self.await_termination_millis_when_shutdown = await_termination_millis_when_shutdown;
400 }
401
402 pub fn set_trace_dispatcher(&mut self, trace_dispatcher: Option<ArcTraceDispatcher>) {
403 self.trace_dispatcher = trace_dispatcher;
404 }
405
406 pub fn set_client_rebalance(&mut self, client_rebalance: bool) {
407 self.client_rebalance = client_rebalance;
408 }
409
410 pub fn set_rpc_hook(&mut self, rpc_hook: Option<Arc<dyn RPCHook>>) {
411 self.rpc_hook = rpc_hook;
412 }
413}
414
415impl Default for ConsumerConfig {
416 fn default() -> Self {
417 ConsumerConfig {
418 consumer_group: CheetahString::new(),
419 topic: CheetahString::new(),
420 sub_expression: CheetahString::new(),
421 message_model: MessageModel::Clustering,
422 consume_from_where: ConsumeFromWhere::ConsumeFromLastOffset,
423 consume_timestamp: Some(CheetahString::from_string(time_utils::time_millis_to_human_string3(
424 (current_millis() - (1000 * 60 * 30)) as i64,
425 ))),
426 allocate_message_queue_strategy: Some(Arc::new(AllocateMessageQueueAveragely)),
427 subscription: Arc::new(HashMap::new()),
428 message_listener: None,
429 message_queue_listener: None,
430 offset_store: None,
431
432 consume_thread_min: 20,
433 consume_thread_max: 64,
434 adjust_thread_pool_nums_threshold: 100_000,
435 consume_concurrently_max_span: 2000,
436 pull_threshold_for_queue: 1000,
437 pop_threshold_for_queue: 96,
438 pull_threshold_size_for_queue: 100,
439 pull_threshold_for_topic: -1,
440 pull_threshold_size_for_topic: -1,
441 pull_interval: 0,
442 consume_message_batch_max_size: 1,
443 pull_batch_size: 32,
444 pull_batch_size_in_bytes: 256 * 1024,
445 post_subscription_when_pull: false,
446 unit_mode: false,
447 max_reconsume_times: -1,
448 suspend_current_queue_time_millis: 1000,
449 consume_timeout: 15,
450 pop_invisible_time: 60000,
451 pop_batch_nums: 32,
452 await_termination_millis_when_shutdown: 0,
453 trace_dispatcher: None,
454 client_rebalance: true,
455 rpc_hook: None,
456 }
457 }
458}
459
460pub struct DefaultMQPushConsumer {
461 client_runtime: Arc<ClientRuntime>,
462 client_config: ClientConfig,
463 consumer_config: Arc<ArcSwap<ConsumerConfig>>,
464 pub(crate) default_mqpush_consumer_impl: Option<Arc<DefaultMQPushConsumerImpl>>,
465}
466
467impl DefaultMQPushConsumer {
468 fn consumer_config_snapshot(&self) -> Arc<ConsumerConfig> {
469 self.consumer_config.load_full()
470 }
471
472 fn update_consumer_config(&self, update: impl Fn(&mut ConsumerConfig)) {
473 self.consumer_config.rcu(|current| {
474 let mut next = (**current).clone();
475 update(&mut next);
476 Arc::new(next)
477 });
478 }
479}
480
481impl MQConsumer for DefaultMQPushConsumer {
482 async fn create_topic(
483 &mut self,
484 key: &str,
485 new_topic: &str,
486 queue_num: i32,
487 attributes: HashMap<String, String>,
488 ) -> crate::ClientResult<()> {
489 self.create_topic_with_flag(key, new_topic, queue_num, 0, attributes)
490 .await
491 }
492
493 async fn create_topic_with_flag(
494 &mut self,
495 key: &str,
496 new_topic: &str,
497 queue_num: i32,
498 topic_sys_flag: i32,
499 attributes: HashMap<String, String>,
500 ) -> crate::ClientResult<()> {
501 let new_topic = self.client_config.with_namespace(CheetahString::from(new_topic));
502 self.default_mqpush_consumer_impl
503 .as_mut()
504 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
505 .create_topic(key, new_topic.as_str(), queue_num, topic_sys_flag, attributes)
506 .await
507 }
508
509 async fn search_offset(&mut self, mq: &MessageQueue, timestamp: u64) -> crate::ClientResult<i64> {
510 let mq = self.client_config.queue_with_namespace(mq.clone());
511 self.default_mqpush_consumer_impl
512 .as_mut()
513 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
514 .search_offset(&mq, timestamp)
515 .await
516 }
517
518 async fn max_offset(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
519 let mq = self.client_config.queue_with_namespace(mq.clone());
520 self.default_mqpush_consumer_impl
521 .as_mut()
522 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
523 .max_offset(&mq)
524 .await
525 }
526
527 async fn min_offset(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
528 let mq = self.client_config.queue_with_namespace(mq.clone());
529 self.default_mqpush_consumer_impl
530 .as_mut()
531 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
532 .min_offset(&mq)
533 .await
534 }
535
536 async fn earliest_msg_store_time(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
537 let mq = self.client_config.queue_with_namespace(mq.clone());
538 self.default_mqpush_consumer_impl
539 .as_mut()
540 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
541 .earliest_msg_store_time(&mq)
542 .await
543 }
544
545 async fn query_message(
546 &mut self,
547 topic: &str,
548 key: &str,
549 max_num: i32,
550 begin: u64,
551 end: u64,
552 ) -> crate::ClientResult<QueryResult> {
553 let topic = self.client_config.with_namespace(CheetahString::from(topic));
554 self.default_mqpush_consumer_impl
555 .as_mut()
556 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
557 .query_message(topic.as_str(), key, max_num, begin, end)
558 .await
559 }
560
561 async fn view_message(&mut self, topic: &str, msg_id: &str) -> crate::ClientResult<MessageExt> {
562 let topic = self.client_config.with_namespace(CheetahString::from(topic));
563 let consumer_impl = self
564 .default_mqpush_consumer_impl
565 .as_mut()
566 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
567 if MessageDecoder::decode_message_id(msg_id).is_ok() {
568 consumer_impl.view_message(topic.as_str(), msg_id).await
569 } else {
570 consumer_impl.query_message_by_uniq_key(topic.as_str(), msg_id).await
571 }
572 }
573
574 async fn send_message_back(
575 &mut self,
576 mut msg: MessageExt,
577 delay_level: i32,
578 broker_name: &str,
579 ) -> crate::ClientResult<()> {
580 let consumer_impl = self
581 .default_mqpush_consumer_impl
582 .as_mut()
583 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
584 let topic = msg.topic().clone();
585 msg.set_topic(self.client_config.with_namespace(topic));
586 let broker_name = (!broker_name.is_empty()).then(|| CheetahString::from(broker_name));
587 consumer_impl
588 .send_message_back_with_broker_name(&mut msg, delay_level, broker_name, None)
589 .await
590 }
591
592 async fn fetch_subscribe_message_queues(&mut self, topic: &str) -> crate::ClientResult<Vec<MessageQueue>> {
593 let topic = self.client_config.with_namespace(CheetahString::from(topic));
594 let consumer_impl = self
595 .default_mqpush_consumer_impl
596 .as_mut()
597 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
598 consumer_impl.fetch_subscribe_message_queues(topic.as_str()).await
599 }
600}
601
602impl MQPushConsumer for DefaultMQPushConsumer {
603 async fn start(&mut self) -> crate::ClientResult<()> {
604 let consumer_config = self.consumer_config_snapshot();
605 let consumer_group = NamespaceUtil::wrap_namespace(
606 self.client_config.get_namespace().unwrap_or_default().as_str(),
607 consumer_config.consumer_group.as_str(),
608 );
609 self.set_consumer_group(consumer_group.as_str());
610 let consumer_impl = self
611 .default_mqpush_consumer_impl
612 .as_mut()
613 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
614 consumer_impl.start().await?;
615
616 let trace_dispatcher_to_start = Self::prepare_trace_dispatcher(
617 &self.client_runtime,
618 &self.client_config,
619 &self.consumer_config,
620 consumer_impl,
621 );
622 if let Some(dispatcher) = trace_dispatcher_to_start {
623 self.start_trace_dispatcher(dispatcher).await;
624 }
625
626 Ok(())
627 }
628
629 async fn shutdown(&mut self) {
630 let consumer_config = self.consumer_config_snapshot();
631 if let Some(ref mut default_mqpush_consumer_impl) = self.default_mqpush_consumer_impl {
632 default_mqpush_consumer_impl
633 .shutdown(consumer_config.await_termination_millis_when_shutdown)
634 .await;
635 }
636 if let Some(ref trace_dispatcher) = consumer_config.trace_dispatcher {
637 if let Some(async_dispatcher) = trace_dispatcher.as_any().downcast_ref::<AsyncTraceDispatcher>() {
638 async_dispatcher.shutdown_async().await;
639 } else {
640 trace_dispatcher.shutdown();
641 }
642 }
643 }
644
645 fn register_message_listener_concurrently<ML>(&mut self, message_listener: ML)
646 where
647 ML: MessageListenerConcurrently + Send + Sync + 'static,
648 {
649 let message_listener = MessageListener {
650 message_listener_concurrently: Some(Arc::new(message_listener)),
651 message_listener_orderly: None,
652 };
653 let message_listener = Some(Arc::new(message_listener));
654 self.update_consumer_config(|config| config.message_listener = message_listener.clone());
655 if let Some(default_mqpush_consumer_impl) = self.default_mqpush_consumer_impl.as_mut() {
656 default_mqpush_consumer_impl.register_message_listener(message_listener);
657 } else {
658 tracing::warn!("DefaultMQPushConsumerImpl is not initialized; listener stored in consumer config");
659 }
660 }
661
662 fn register_message_listener_orderly<ML>(&mut self, message_listener: ML)
663 where
664 ML: MessageListenerOrderly + Send + Sync + 'static,
665 {
666 let message_listener = MessageListener {
667 message_listener_concurrently: None,
668 message_listener_orderly: Some(Arc::new(message_listener)),
669 };
670 let message_listener = Some(Arc::new(message_listener));
671 self.update_consumer_config(|config| config.message_listener = message_listener.clone());
672 if let Some(default_mqpush_consumer_impl) = self.default_mqpush_consumer_impl.as_mut() {
673 default_mqpush_consumer_impl.register_message_listener(message_listener);
674 } else {
675 tracing::warn!("DefaultMQPushConsumerImpl is not initialized; listener stored in consumer config");
676 }
677 }
678
679 async fn subscribe(
680 &mut self,
681 topic: impl Into<CheetahString>,
682 sub_expression: impl Into<CheetahString>,
683 ) -> crate::ClientResult<()> {
684 let topic = self.client_config.with_namespace(topic);
685 let sub_expression = sub_expression.into();
686
687 self.default_mqpush_consumer_impl
688 .as_mut()
689 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?
690 .subscribe(topic, sub_expression)
691 .await
692 }
693
694 async fn subscribe_with_selector(
695 &mut self,
696 topic: &str,
697 selector: Option<MessageSelector>,
698 ) -> crate::ClientResult<()> {
699 let consumer_impl = self
700 .default_mqpush_consumer_impl
701 .as_mut()
702 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
703 let topic = self.client_config.with_namespace(CheetahString::from(topic));
704 consumer_impl.subscribe_with_selector(topic, selector).await
705 }
706
707 async fn unsubscribe(&mut self, topic: &str) {
708 if let Some(ref mut default_mqpush_consumer_impl) = self.default_mqpush_consumer_impl {
709 default_mqpush_consumer_impl.unsubscribe(topic).await;
710 }
711 }
712
713 async fn suspend(&self) {
714 if let Some(ref default_mqpush_consumer_impl) = self.default_mqpush_consumer_impl {
715 default_mqpush_consumer_impl.suspend().await;
716 }
717 }
718
719 async fn resume(&self) {
720 if let Some(ref default_mqpush_consumer_impl) = self.default_mqpush_consumer_impl {
721 default_mqpush_consumer_impl.resume().await;
722 }
723 }
724
725 fn update_core_pool_size(&self, core_pool_size: usize) -> crate::ClientResult<()> {
726 let consumer_impl = self
727 .default_mqpush_consumer_impl
728 .as_ref()
729 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
730 consumer_impl.update_core_pool_size(core_pool_size);
731 Ok(())
732 }
733}
734
735impl DefaultMQPushConsumer {
736 pub fn builder(client_runtime: Arc<ClientRuntime>) -> DefaultMQPushConsumerBuilder {
737 DefaultMQPushConsumerBuilder::new(client_runtime)
738 }
739
740 pub async fn start(&mut self) -> crate::ClientResult<()> {
741 <Self as MQPushConsumer>::start(self).await
742 }
743
744 pub async fn shutdown(&mut self) {
745 <Self as MQPushConsumer>::shutdown(self).await;
746 }
747
748 pub async fn create_topic(
749 &mut self,
750 key: &str,
751 new_topic: &str,
752 queue_num: i32,
753 attributes: HashMap<String, String>,
754 ) -> crate::ClientResult<()> {
755 <Self as MQConsumer>::create_topic(self, key, new_topic, queue_num, attributes).await
756 }
757
758 pub async fn create_topic_with_flag(
759 &mut self,
760 key: &str,
761 new_topic: &str,
762 queue_num: i32,
763 topic_sys_flag: i32,
764 attributes: HashMap<String, String>,
765 ) -> crate::ClientResult<()> {
766 <Self as MQConsumer>::create_topic_with_flag(self, key, new_topic, queue_num, topic_sys_flag, attributes).await
767 }
768
769 pub async fn search_offset(&mut self, mq: &MessageQueue, timestamp: u64) -> crate::ClientResult<i64> {
770 <Self as MQConsumer>::search_offset(self, mq, timestamp).await
771 }
772
773 pub async fn max_offset(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
774 <Self as MQConsumer>::max_offset(self, mq).await
775 }
776
777 pub async fn min_offset(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
778 <Self as MQConsumer>::min_offset(self, mq).await
779 }
780
781 pub async fn earliest_msg_store_time(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
782 <Self as MQConsumer>::earliest_msg_store_time(self, mq).await
783 }
784
785 pub async fn query_message(
786 &mut self,
787 topic: &str,
788 key: &str,
789 max_num: i32,
790 begin: u64,
791 end: u64,
792 ) -> crate::ClientResult<QueryResult> {
793 <Self as MQConsumer>::query_message(self, topic, key, max_num, begin, end).await
794 }
795
796 pub async fn view_message(&mut self, topic: &str, msg_id: &str) -> crate::ClientResult<MessageExt> {
797 <Self as MQConsumer>::view_message(self, topic, msg_id).await
798 }
799
800 pub async fn send_message_back(
801 &mut self,
802 msg: MessageExt,
803 delay_level: i32,
804 broker_name: &str,
805 ) -> crate::ClientResult<()> {
806 <Self as MQConsumer>::send_message_back(self, msg, delay_level, broker_name).await
807 }
808
809 pub async fn send_message_back_to_origin_broker(
810 &mut self,
811 msg: MessageExt,
812 delay_level: i32,
813 ) -> crate::ClientResult<()> {
814 <Self as MQConsumer>::send_message_back_to_origin_broker(self, msg, delay_level).await
815 }
816
817 pub async fn fetch_subscribe_message_queues(&mut self, topic: &str) -> crate::ClientResult<Vec<MessageQueue>> {
818 <Self as MQConsumer>::fetch_subscribe_message_queues(self, topic).await
819 }
820
821 pub async fn subscribe(
822 &mut self,
823 topic: impl Into<CheetahString>,
824 sub_expression: impl Into<CheetahString>,
825 ) -> crate::ClientResult<()> {
826 <Self as MQPushConsumer>::subscribe(self, topic, sub_expression).await
827 }
828
829 pub async fn subscribe_with_selector(
830 &mut self,
831 topic: &str,
832 selector: Option<MessageSelector>,
833 ) -> crate::ClientResult<()> {
834 <Self as MQPushConsumer>::subscribe_with_selector(self, topic, selector).await
835 }
836
837 pub async fn unsubscribe(&mut self, topic: &str) {
838 <Self as MQPushConsumer>::unsubscribe(self, topic).await;
839 }
840
841 pub async fn suspend(&self) {
842 <Self as MQPushConsumer>::suspend(self).await;
843 }
844
845 pub async fn resume(&self) {
846 <Self as MQPushConsumer>::resume(self).await;
847 }
848
849 pub fn update_core_pool_size(&self, core_pool_size: usize) -> crate::ClientResult<()> {
850 <Self as MQPushConsumer>::update_core_pool_size(self, core_pool_size)
851 }
852
853 pub async fn consumer_running_info(&self) -> crate::ClientResult<ConsumerRunningInfo> {
855 let consumer_impl = self
856 .default_mqpush_consumer_impl
857 .as_ref()
858 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
859 Ok(MQConsumerInner::consumer_running_info(consumer_impl.as_ref()).await)
860 }
861
862 fn prepare_trace_dispatcher(
863 client_runtime: &Arc<ClientRuntime>,
864 client_config: &ClientConfig,
865 consumer_config: &Arc<ArcSwap<ConsumerConfig>>,
866 consumer_impl: &Arc<DefaultMQPushConsumerImpl>,
867 ) -> Option<ArcTraceDispatcher> {
868 let consumer_config_snapshot = consumer_config.load_full();
869 let dispatcher = match consumer_config_snapshot.trace_dispatcher.clone() {
870 Some(dispatcher) => dispatcher,
871 None if client_config.enable_trace => {
872 let trace_topic = client_config
873 .trace_topic
874 .as_ref()
875 .map(|topic| topic.as_str())
876 .unwrap_or_default();
877 let dispatcher = AsyncTraceDispatcher::new(
878 Arc::clone(client_runtime),
879 consumer_config_snapshot.consumer_group.as_str(),
880 Type::Consume,
881 client_config.trace_msg_batch_num,
882 trace_topic,
883 consumer_config_snapshot.rpc_hook.clone(),
884 );
885 Arc::new(dispatcher)
886 }
887 None => return None,
888 };
889
890 if let Some(async_dispatcher) = dispatcher.as_any().downcast_ref::<AsyncTraceDispatcher>() {
891 async_dispatcher.set_client_host(consumer_impl.client_id());
892 async_dispatcher.set_namespace_v2(client_config.namespace_v2.clone());
893 async_dispatcher.set_use_tls(client_config.use_tls);
894 }
895
896 consumer_config.rcu(|current| {
897 let mut next = (**current).clone();
898 next.trace_dispatcher = Some(dispatcher.clone());
899 Arc::new(next)
900 });
901 consumer_impl.register_consume_message_hook(ConsumeMessageTraceHookImpl::new(dispatcher.clone()));
902 Some(dispatcher)
903 }
904
905 async fn start_trace_dispatcher(&self, dispatcher: ArcTraceDispatcher) {
906 let name_server_addr = self
907 .client_config
908 .namesrv_addr
909 .as_ref()
910 .map(|addr| addr.as_str())
911 .unwrap_or_default();
912 if let Err(error) = dispatcher.start(name_server_addr, self.client_config.access_channel) {
913 tracing::warn!("trace dispatcher start failed: {}", error);
914 }
915 }
916
917 pub fn is_pause(&self) -> bool {
921 self.default_mqpush_consumer_impl
922 .as_ref()
923 .is_some_and(|consumer_impl| consumer_impl.is_pause())
924 }
925
926 pub fn is_consume_orderly(&self) -> bool {
930 self.default_mqpush_consumer_impl
931 .as_ref()
932 .is_some_and(|consumer_impl| consumer_impl.is_consume_orderly())
933 }
934
935 pub fn register_consume_message_hook(
939 &mut self,
940 hook: impl ConsumeMessageHook + 'static,
941 ) -> crate::ClientResult<()> {
942 let consumer_impl = self
943 .default_mqpush_consumer_impl
944 .as_mut()
945 .ok_or_else(|| crate::ClientError::not_initialized("DefaultMQPushConsumerImpl"))?;
946 consumer_impl.register_consume_message_hook(hook);
947 Ok(())
948 }
949
950 pub fn default_mq_push_consumer_impl(&self) -> Option<&Arc<DefaultMQPushConsumerImpl>> {
951 self.default_mqpush_consumer_impl.as_ref()
952 }
953
954 pub fn get_default_mq_push_consumer_impl(&self) -> Option<&Arc<DefaultMQPushConsumerImpl>> {
955 self.default_mq_push_consumer_impl()
956 }
957
958 pub fn message_listener(&self) -> Option<Arc<MessageListener>> {
959 self.consumer_config_snapshot().message_listener.clone()
960 }
961
962 pub fn get_message_listener(&self) -> Option<Arc<MessageListener>> {
963 self.message_listener()
964 }
965
966 pub fn set_message_listener(&mut self, message_listener: Option<Arc<MessageListener>>) {
967 self.update_consumer_config(|config| config.message_listener = message_listener.clone());
968 if let Some(consumer_impl) = self.default_mqpush_consumer_impl.as_mut() {
969 consumer_impl.register_message_listener(message_listener);
970 }
971 }
972
973 pub fn register_message_listener(&mut self, message_listener: Option<Arc<MessageListener>>) {
974 self.set_message_listener(message_listener);
975 }
976
977 pub fn allocate_message_queue_strategy(&self) -> Option<Arc<dyn AllocateMessageQueueStrategy>> {
978 self.consumer_config_snapshot().allocate_message_queue_strategy.clone()
979 }
980
981 pub fn get_allocate_message_queue_strategy(&self) -> Option<Arc<dyn AllocateMessageQueueStrategy>> {
982 self.allocate_message_queue_strategy()
983 }
984
985 pub fn set_allocate_message_queue_strategy(
986 &mut self,
987 allocate_message_queue_strategy: Arc<dyn AllocateMessageQueueStrategy>,
988 ) {
989 self.update_consumer_config(|config| {
990 config.set_allocate_message_queue_strategy(allocate_message_queue_strategy.clone())
991 });
992 }
993
994 pub fn consume_concurrently_max_span(&self) -> u32 {
995 self.consumer_config_snapshot().consume_concurrently_max_span
996 }
997
998 pub fn get_consume_concurrently_max_span(&self) -> u32 {
999 self.consume_concurrently_max_span()
1000 }
1001
1002 pub fn set_consume_concurrently_max_span(&mut self, consume_concurrently_max_span: u32) {
1003 self.update_consumer_config(|config| config.set_consume_concurrently_max_span(consume_concurrently_max_span));
1004 }
1005
1006 pub fn consume_from_where(&self) -> ConsumeFromWhere {
1007 self.consumer_config_snapshot().consume_from_where
1008 }
1009
1010 pub fn get_consume_from_where(&self) -> ConsumeFromWhere {
1011 self.consume_from_where()
1012 }
1013
1014 pub fn set_consume_from_where(&mut self, consume_from_where: ConsumeFromWhere) {
1015 self.update_consumer_config(|config| config.set_consume_from_where(consume_from_where));
1016 self.sync_rebalance_consumer_config();
1017 }
1018
1019 pub fn consume_message_batch_max_size(&self) -> u32 {
1020 self.consumer_config_snapshot().consume_message_batch_max_size
1021 }
1022
1023 pub fn get_consume_message_batch_max_size(&self) -> u32 {
1024 self.consume_message_batch_max_size()
1025 }
1026
1027 pub fn set_consume_message_batch_max_size(&mut self, consume_message_batch_max_size: u32) {
1028 self.update_consumer_config(|config| config.set_consume_message_batch_max_size(consume_message_batch_max_size));
1029 }
1030
1031 pub fn consumer_group(&self) -> CheetahString {
1032 self.consumer_config_snapshot().consumer_group.clone()
1033 }
1034
1035 pub fn get_consumer_group(&self) -> CheetahString {
1036 self.consumer_group()
1037 }
1038
1039 pub fn get_subscription(&self) -> Arc<HashMap<CheetahString, CheetahString>> {
1040 self.consumer_config_snapshot().subscription()
1041 }
1042
1043 #[inline]
1044 pub fn set_consumer_group(&mut self, consumer_group: impl Into<CheetahString>) {
1045 let consumer_group = consumer_group.into();
1046 self.update_consumer_config(|config| config.set_consumer_group(consumer_group.clone()));
1047 }
1048
1049 pub fn consume_thread_max(&self) -> u32 {
1050 self.consumer_config_snapshot().consume_thread_max
1051 }
1052
1053 pub fn get_consume_thread_max(&self) -> u32 {
1054 self.consume_thread_max()
1055 }
1056
1057 pub fn set_consume_thread_max(&mut self, consume_thread_max: u32) {
1058 self.update_consumer_config(|config| config.set_consume_thread_max(consume_thread_max));
1059 }
1060
1061 pub fn consume_thread_min(&self) -> u32 {
1062 self.consumer_config_snapshot().consume_thread_min
1063 }
1064
1065 pub fn get_consume_thread_min(&self) -> u32 {
1066 self.consume_thread_min()
1067 }
1068
1069 pub fn set_consume_thread_min(&mut self, consume_thread_min: u32) {
1070 self.update_consumer_config(|config| config.set_consume_thread_min(consume_thread_min));
1071 }
1072
1073 pub fn message_model(&self) -> MessageModel {
1074 self.consumer_config_snapshot().message_model
1075 }
1076
1077 pub fn get_message_model(&self) -> MessageModel {
1078 self.message_model()
1079 }
1080
1081 pub fn set_message_model(&mut self, message_model: MessageModel) {
1082 self.update_consumer_config(|config| config.set_message_model(message_model));
1083 self.sync_rebalance_consumer_config();
1084 }
1085
1086 pub fn pull_batch_size(&self) -> u32 {
1087 self.consumer_config_snapshot().pull_batch_size
1088 }
1089
1090 pub fn get_pull_batch_size(&self) -> u32 {
1091 self.pull_batch_size()
1092 }
1093
1094 pub fn set_pull_batch_size(&mut self, pull_batch_size: u32) {
1095 self.update_consumer_config(|config| config.set_pull_batch_size(pull_batch_size));
1096 }
1097
1098 pub fn pull_interval(&self) -> u64 {
1099 self.consumer_config_snapshot().pull_interval
1100 }
1101
1102 pub fn get_pull_interval(&self) -> u64 {
1103 self.pull_interval()
1104 }
1105
1106 pub fn set_pull_interval(&mut self, pull_interval: u64) {
1107 self.update_consumer_config(|config| config.set_pull_interval(pull_interval));
1108 }
1109
1110 pub fn pull_threshold_for_queue(&self) -> u32 {
1111 self.consumer_config_snapshot().pull_threshold_for_queue
1112 }
1113
1114 pub fn get_pull_threshold_for_queue(&self) -> u32 {
1115 self.pull_threshold_for_queue()
1116 }
1117
1118 pub fn set_pull_threshold_for_queue(&mut self, pull_threshold_for_queue: u32) {
1119 self.update_consumer_config(|config| config.set_pull_threshold_for_queue(pull_threshold_for_queue));
1120 self.sync_rebalance_consumer_config();
1121 }
1122
1123 pub fn pop_threshold_for_queue(&self) -> u32 {
1124 self.consumer_config_snapshot().pop_threshold_for_queue
1125 }
1126
1127 pub fn get_pop_threshold_for_queue(&self) -> u32 {
1128 self.pop_threshold_for_queue()
1129 }
1130
1131 pub fn set_pop_threshold_for_queue(&mut self, pop_threshold_for_queue: u32) {
1132 self.update_consumer_config(|config| config.set_pop_threshold_for_queue(pop_threshold_for_queue));
1133 }
1134
1135 pub fn pull_threshold_for_topic(&self) -> i32 {
1136 self.consumer_config_snapshot().pull_threshold_for_topic
1137 }
1138
1139 pub fn get_pull_threshold_for_topic(&self) -> i32 {
1140 self.pull_threshold_for_topic()
1141 }
1142
1143 pub fn set_pull_threshold_for_topic(&mut self, pull_threshold_for_topic: i32) {
1144 self.update_consumer_config(|config| config.set_pull_threshold_for_topic(pull_threshold_for_topic));
1145 self.sync_rebalance_consumer_config();
1146 }
1147
1148 pub fn pull_threshold_size_for_queue(&self) -> u32 {
1149 self.consumer_config_snapshot().pull_threshold_size_for_queue
1150 }
1151
1152 pub fn get_pull_threshold_size_for_queue(&self) -> u32 {
1153 self.pull_threshold_size_for_queue()
1154 }
1155
1156 pub fn set_pull_threshold_size_for_queue(&mut self, pull_threshold_size_for_queue: u32) {
1157 self.update_consumer_config(|config| config.set_pull_threshold_size_for_queue(pull_threshold_size_for_queue));
1158 self.sync_rebalance_consumer_config();
1159 }
1160
1161 pub fn pull_threshold_size_for_topic(&self) -> i32 {
1162 self.consumer_config_snapshot().pull_threshold_size_for_topic
1163 }
1164
1165 pub fn get_pull_threshold_size_for_topic(&self) -> i32 {
1166 self.pull_threshold_size_for_topic()
1167 }
1168
1169 pub fn set_pull_threshold_size_for_topic(&mut self, pull_threshold_size_for_topic: i32) {
1170 self.update_consumer_config(|config| config.set_pull_threshold_size_for_topic(pull_threshold_size_for_topic));
1171 self.sync_rebalance_consumer_config();
1172 }
1173
1174 pub fn consume_timestamp(&self) -> Option<CheetahString> {
1175 self.consumer_config_snapshot().consume_timestamp.clone()
1176 }
1177
1178 pub fn get_consume_timestamp(&self) -> Option<CheetahString> {
1179 self.consume_timestamp()
1180 }
1181
1182 pub fn set_consume_timestamp(&mut self, consume_timestamp: impl Into<CheetahString>) {
1183 let consume_timestamp = consume_timestamp.into();
1184 self.update_consumer_config(|config| config.set_consume_timestamp(Some(consume_timestamp.clone())));
1185 self.sync_rebalance_consumer_config();
1186 }
1187
1188 pub fn clear_consume_timestamp(&mut self) {
1189 self.update_consumer_config(|config| config.set_consume_timestamp(None));
1190 self.sync_rebalance_consumer_config();
1191 }
1192
1193 pub fn is_post_subscription_when_pull(&self) -> bool {
1194 self.consumer_config_snapshot().post_subscription_when_pull
1195 }
1196
1197 pub fn set_post_subscription_when_pull(&mut self, post_subscription_when_pull: bool) {
1198 self.update_consumer_config(|config| config.set_post_subscription_when_pull(post_subscription_when_pull));
1199 }
1200
1201 pub fn is_unit_mode(&self) -> bool {
1202 self.consumer_config_snapshot().unit_mode
1203 }
1204
1205 pub fn set_unit_mode(&mut self, unit_mode: bool) {
1206 self.update_consumer_config(|config| config.set_unit_mode(unit_mode));
1207 }
1208
1209 pub fn adjust_thread_pool_nums_threshold(&self) -> u64 {
1210 self.consumer_config_snapshot().adjust_thread_pool_nums_threshold
1211 }
1212
1213 pub fn get_adjust_thread_pool_nums_threshold(&self) -> u64 {
1214 self.adjust_thread_pool_nums_threshold()
1215 }
1216
1217 pub fn set_adjust_thread_pool_nums_threshold(&mut self, adjust_thread_pool_nums_threshold: u64) {
1218 self.update_consumer_config(|config| {
1219 config.set_adjust_thread_pool_nums_threshold(adjust_thread_pool_nums_threshold)
1220 });
1221 }
1222
1223 pub fn max_reconsume_times(&self) -> i32 {
1224 self.consumer_config_snapshot().max_reconsume_times
1225 }
1226
1227 pub fn get_max_reconsume_times(&self) -> i32 {
1228 self.max_reconsume_times()
1229 }
1230
1231 pub fn set_max_reconsume_times(&mut self, max_reconsume_times: i32) {
1232 self.update_consumer_config(|config| config.set_max_reconsume_times(max_reconsume_times));
1233 }
1234
1235 pub fn suspend_current_queue_time_millis(&self) -> u64 {
1236 self.consumer_config_snapshot().suspend_current_queue_time_millis
1237 }
1238
1239 pub fn get_suspend_current_queue_time_millis(&self) -> u64 {
1240 self.suspend_current_queue_time_millis()
1241 }
1242
1243 pub fn set_suspend_current_queue_time_millis(&mut self, suspend_current_queue_time_millis: u64) {
1244 self.update_consumer_config(|config| {
1245 config.set_suspend_current_queue_time_millis(suspend_current_queue_time_millis)
1246 });
1247 }
1248
1249 pub fn consume_timeout(&self) -> u64 {
1250 self.consumer_config_snapshot().consume_timeout
1251 }
1252
1253 pub fn get_consume_timeout(&self) -> u64 {
1254 self.consume_timeout()
1255 }
1256
1257 pub fn set_consume_timeout(&mut self, consume_timeout: u64) {
1258 self.update_consumer_config(|config| config.set_consume_timeout(consume_timeout));
1259 }
1260
1261 pub fn pop_invisible_time(&self) -> u64 {
1262 self.consumer_config_snapshot().pop_invisible_time
1263 }
1264
1265 pub fn get_pop_invisible_time(&self) -> u64 {
1266 self.pop_invisible_time()
1267 }
1268
1269 pub fn set_pop_invisible_time(&mut self, pop_invisible_time: u64) {
1270 self.update_consumer_config(|config| config.set_pop_invisible_time(pop_invisible_time));
1271 }
1272
1273 pub fn await_termination_millis_when_shutdown(&self) -> u64 {
1274 self.consumer_config_snapshot().await_termination_millis_when_shutdown
1275 }
1276
1277 pub fn get_await_termination_millis_when_shutdown(&self) -> u64 {
1278 self.await_termination_millis_when_shutdown()
1279 }
1280
1281 pub fn set_await_termination_millis_when_shutdown(&mut self, await_termination_millis_when_shutdown: u64) {
1282 self.update_consumer_config(|config| {
1283 config.set_await_termination_millis_when_shutdown(await_termination_millis_when_shutdown)
1284 });
1285 }
1286
1287 pub fn pull_batch_size_in_bytes(&self) -> u32 {
1288 self.consumer_config_snapshot().pull_batch_size_in_bytes
1289 }
1290
1291 pub fn get_pull_batch_size_in_bytes(&self) -> u32 {
1292 self.pull_batch_size_in_bytes()
1293 }
1294
1295 pub fn set_pull_batch_size_in_bytes(&mut self, pull_batch_size_in_bytes: u32) {
1296 self.update_consumer_config(|config| config.set_pull_batch_size_in_bytes(pull_batch_size_in_bytes));
1297 }
1298
1299 pub fn trace_dispatcher(&self) -> Option<ArcTraceDispatcher> {
1300 self.consumer_config_snapshot().trace_dispatcher.clone()
1301 }
1302
1303 pub fn get_trace_dispatcher(&self) -> Option<ArcTraceDispatcher> {
1304 self.trace_dispatcher()
1305 }
1306
1307 pub fn is_use_tls(&self) -> bool {
1308 self.client_config.is_use_tls()
1309 }
1310
1311 pub fn set_use_tls(&mut self, use_tls: bool) {
1312 self.client_config.set_use_tls(use_tls);
1313 if let Some(consumer_impl) = self.default_mqpush_consumer_impl.as_mut() {
1314 consumer_impl.set_use_tls(use_tls);
1315 }
1316 if let Some(trace_dispatcher) = self.consumer_config_snapshot().trace_dispatcher.as_ref() {
1317 if let Some(async_dispatcher) = trace_dispatcher.as_any().downcast_ref::<AsyncTraceDispatcher>() {
1318 async_dispatcher.set_use_tls(use_tls);
1319 }
1320 }
1321 }
1322
1323 pub fn offset_store(&self) -> Option<Arc<OffsetStore>> {
1324 self.consumer_config_snapshot().offset_store().or_else(|| {
1325 self.default_mqpush_consumer_impl
1326 .as_ref()
1327 .and_then(|consumer_impl| consumer_impl.offset_store())
1328 })
1329 }
1330
1331 pub fn get_offset_store(&self) -> Option<Arc<OffsetStore>> {
1332 self.offset_store()
1333 }
1334
1335 pub fn set_offset_store(&mut self, offset_store: Option<Arc<OffsetStore>>) {
1336 self.update_consumer_config(|config| config.set_offset_store(offset_store.clone()));
1337 if let Some(consumer_impl) = self.default_mqpush_consumer_impl.as_mut() {
1338 consumer_impl.set_offset_store(offset_store);
1339 }
1340 }
1341
1342 pub fn pop_batch_nums(&self) -> u32 {
1343 self.consumer_config_snapshot().pop_batch_nums
1344 }
1345
1346 pub fn get_pop_batch_nums(&self) -> u32 {
1347 self.pop_batch_nums()
1348 }
1349
1350 pub fn set_pop_batch_nums(&mut self, pop_batch_nums: u32) {
1351 self.update_consumer_config(|config| config.set_pop_batch_nums(pop_batch_nums));
1352 }
1353
1354 pub fn is_client_rebalance(&self) -> bool {
1355 self.consumer_config_snapshot().client_rebalance
1356 }
1357
1358 pub fn set_client_rebalance(&mut self, client_rebalance: bool) {
1359 self.update_consumer_config(|config| config.set_client_rebalance(client_rebalance));
1360 self.sync_rebalance_consumer_config();
1361 }
1362
1363 pub fn message_queue_listener(&self) -> Option<ArcMessageQueueListener> {
1364 self.consumer_config_snapshot().message_queue_listener.clone()
1365 }
1366
1367 pub fn get_message_queue_listener(&self) -> Option<ArcMessageQueueListener> {
1368 self.message_queue_listener()
1369 }
1370
1371 pub fn set_message_queue_listener(&mut self, message_queue_listener: Option<ArcMessageQueueListener>) {
1372 self.update_consumer_config(|config| config.set_message_queue_listener(message_queue_listener.clone()));
1373 self.sync_rebalance_consumer_config();
1374 }
1375
1376 pub fn apply_tuning_profile(&mut self, profile: ConsumerTuningProfile) {
1377 self.update_consumer_config(|config| config.apply_tuning_profile(profile));
1378 self.sync_rebalance_consumer_config();
1379 }
1380
1381 fn sync_rebalance_consumer_config(&self) {
1382 if let Some(consumer_impl) = self.default_mqpush_consumer_impl.as_ref() {
1383 consumer_impl.sync_rebalance_consumer_config((*self.consumer_config_snapshot()).clone());
1384 }
1385 }
1386
1387 pub fn new(
1388 client_runtime: Arc<ClientRuntime>,
1389 client_config: ClientConfig,
1390 consumer_config: ConsumerConfig,
1391 ) -> DefaultMQPushConsumer {
1392 Self::new_with_options(client_runtime, ClientOptions::legacy(client_config), consumer_config)
1393 }
1394
1395 pub(crate) fn new_with_options(
1396 client_runtime: Arc<ClientRuntime>,
1397 options: ClientOptions,
1398 consumer_config: ConsumerConfig,
1399 ) -> DefaultMQPushConsumer {
1400 let rpc_hook = consumer_config.rpc_hook.clone();
1401 let client_config = options.client_config().clone();
1402 let nameserver_discovery = options.nameserver_discovery().cloned();
1403 let consumer_config = Arc::new(ArcSwap::from_pointee(consumer_config));
1404 let default_mqpush_consumer_impl = Arc::new(DefaultMQPushConsumerImpl::new_with_config_store_and_discovery(
1405 Arc::clone(&client_runtime),
1406 client_config.clone(),
1407 nameserver_discovery,
1408 consumer_config.clone(),
1409 rpc_hook,
1410 ));
1411 default_mqpush_consumer_impl.initialize_self_reference();
1412 DefaultMQPushConsumer {
1413 client_runtime,
1414 client_config,
1415 consumer_config,
1416 default_mqpush_consumer_impl: Some(default_mqpush_consumer_impl),
1417 }
1418 }
1419
1420 pub fn set_name_server_addr(&mut self, name_server_addr: CheetahString) {
1421 self.client_config.namesrv_addr = Some(name_server_addr);
1422 self.client_config
1423 .namespace_initialized
1424 .store(false, std::sync::atomic::Ordering::Release);
1425 }
1426}
1427
1428#[cfg(test)]
1429mod tests {
1430 use crate::test_support::error_assertions::assert_not_initialized;
1431 use std::any::Any;
1432 use std::collections::HashSet;
1433 use std::sync::atomic::AtomicUsize;
1434 use std::sync::atomic::Ordering;
1435 use std::sync::Arc;
1436 use std::sync::Mutex as StdMutex;
1437
1438 use super::*;
1439
1440 fn test_runtime() -> Arc<ClientRuntime> {
1441 crate::runtime::test_client_runtime("default-push-consumer-test")
1442 }
1443 use crate::base::access_channel::AccessChannel;
1444 use crate::consumer::listener::consume_concurrently_context::ConsumeConcurrentlyContext;
1445 use crate::consumer::listener::consume_concurrently_status::ConsumeConcurrentlyStatus;
1446 use crate::consumer::listener::consume_orderly_context::ConsumeOrderlyContext;
1447 use crate::consumer::listener::consume_orderly_status::ConsumeOrderlyStatus;
1448 use crate::consumer::message_queue_listener::MessageQueueListener;
1449 use crate::consumer::mq_consumer_inner::MQConsumerInner;
1450 use crate::consumer::store::read_offset_type::ReadOffsetType;
1451 use crate::hook::consume_message_context::ConsumeMessageContext;
1452 use crate::hook::consume_message_hook::ConsumeMessageHook;
1453 use crate::trace::trace_dispatcher::TraceDispatcher;
1454
1455 #[derive(Default)]
1456 struct CapturingTraceDispatcher {
1457 start_count: AtomicUsize,
1458 shutdown_count: AtomicUsize,
1459 append_count: AtomicUsize,
1460 last_name_srv_addr: StdMutex<Option<String>>,
1461 last_access_channel: StdMutex<Option<AccessChannel>>,
1462 }
1463
1464 impl TraceDispatcher for CapturingTraceDispatcher {
1465 fn start(&self, name_srv_addr: &str, access_channel: AccessChannel) -> crate::ClientResult<()> {
1466 self.start_count.fetch_add(1, Ordering::SeqCst);
1467 *self.last_name_srv_addr.lock().expect("name server lock") = Some(name_srv_addr.to_string());
1468 *self.last_access_channel.lock().expect("access channel lock") = Some(access_channel);
1469 Ok(())
1470 }
1471
1472 fn append(&self, _ctx: &dyn Any) -> bool {
1473 self.append_count.fetch_add(1, Ordering::SeqCst);
1474 true
1475 }
1476
1477 fn flush(&self) -> crate::ClientResult<()> {
1478 Ok(())
1479 }
1480
1481 fn shutdown(&self) {
1482 self.shutdown_count.fetch_add(1, Ordering::SeqCst);
1483 }
1484
1485 fn as_any(&self) -> &dyn Any {
1486 self
1487 }
1488
1489 fn as_mut_any(&mut self) -> &mut dyn Any {
1490 self
1491 }
1492 }
1493
1494 struct TestConcurrentListener;
1495
1496 impl MessageListenerConcurrently for TestConcurrentListener {
1497 fn consume_message(
1498 &self,
1499 _msgs: &[&MessageExt],
1500 _context: &ConsumeConcurrentlyContext,
1501 ) -> crate::ClientResult<ConsumeConcurrentlyStatus> {
1502 Ok(ConsumeConcurrentlyStatus::ConsumeSuccess)
1503 }
1504 }
1505
1506 struct TestConsumeHook;
1507
1508 impl ConsumeMessageHook for TestConsumeHook {
1509 fn hook_name(&self) -> &'static str {
1510 "TestConsumeHook"
1511 }
1512
1513 fn consume_message_before(&self, _context: &mut ConsumeMessageContext) {}
1514
1515 fn consume_message_after(&self, _context: &mut ConsumeMessageContext) {}
1516 }
1517
1518 struct TestMessageQueueListener;
1519
1520 impl MessageQueueListener for TestMessageQueueListener {
1521 fn message_queue_changed(
1522 &self,
1523 _topic: &str,
1524 _mq_all: &HashSet<MessageQueue>,
1525 _mq_assigned: &HashSet<MessageQueue>,
1526 ) {
1527 }
1528 }
1529
1530 fn namespaced_push_consumer() -> DefaultMQPushConsumer {
1531 let mut client_config = ClientConfig::default();
1532 client_config.set_namespace(CheetahString::from_static_str("ns"));
1533
1534 DefaultMQPushConsumer::builder(test_runtime())
1535 .consumer_group("push_namespace_group")
1536 .client_config(client_config)
1537 .build()
1538 }
1539
1540 #[test]
1541 fn builder_preserves_default_allocate_message_queue_strategy() {
1542 let consumer = DefaultMQPushConsumer::builder(test_runtime())
1543 .consumer_group("builder_default_strategy_group")
1544 .build();
1545
1546 let consumer_config = consumer.consumer_config_snapshot();
1547 let strategy = consumer_config
1548 .allocate_message_queue_strategy
1549 .as_ref()
1550 .expect("default allocation strategy should be preserved");
1551 assert_eq!("AVG", strategy.get_name());
1552 }
1553
1554 #[tokio::test]
1555 async fn subscribe_without_impl_returns_not_initialized_error() {
1556 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1557 .consumer_group("push_missing_impl_group")
1558 .build();
1559 consumer.default_mqpush_consumer_impl = None;
1560
1561 let error = consumer
1562 .subscribe("topic", "*")
1563 .await
1564 .expect_err("subscribe without impl should fail");
1565
1566 assert_not_initialized(&error, "DefaultMQPushConsumerImpl");
1567 }
1568
1569 #[tokio::test]
1570 async fn mq_admin_facade_without_impl_returns_not_initialized_error() {
1571 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1572 .consumer_group("push_missing_admin_impl_group")
1573 .build();
1574 consumer.default_mqpush_consumer_impl = None;
1575 let mq = MessageQueue::from_parts("TopicA", "broker-a", 0);
1576
1577 let max_error = MQConsumer::max_offset(&mut consumer, &mq)
1578 .await
1579 .expect_err("maxOffset without impl should fail");
1580 let query_error = MQConsumer::query_message(&mut consumer, "TopicA", "KeyA", 32, 0, 1)
1581 .await
1582 .expect_err("queryMessage without impl should fail");
1583 let view_error = MQConsumer::view_message(&mut consumer, "TopicA", "bad-msg-id")
1584 .await
1585 .expect_err("viewMessage without impl should fail");
1586
1587 assert_not_initialized(&max_error, "DefaultMQPushConsumerImpl");
1588 assert_not_initialized(&query_error, "DefaultMQPushConsumerImpl");
1589 assert_not_initialized(&view_error, "DefaultMQPushConsumerImpl");
1590 }
1591
1592 #[tokio::test]
1593 async fn consumer_running_info_without_impl_returns_not_initialized_error() {
1594 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1595 .consumer_group("push_missing_running_info_impl_group")
1596 .build();
1597 consumer.default_mqpush_consumer_impl = None;
1598
1599 let error = consumer
1600 .consumer_running_info()
1601 .await
1602 .expect_err("running info without impl should fail");
1603
1604 assert_not_initialized(&error, "DefaultMQPushConsumerImpl");
1605 }
1606
1607 #[tokio::test]
1608 async fn consumer_running_info_facade_returns_impl_snapshot_like_java_admin() {
1609 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1610 .consumer_group("push_running_info_group")
1611 .consume_thread_min(7)
1612 .consume_thread_max(11)
1613 .pull_batch_size(13)
1614 .consume_message_batch_max_size(3)
1615 .build();
1616
1617 consumer
1618 .subscribe("TopicRunningInfo", "TagA")
1619 .await
1620 .expect("subscribe should update running-info subscriptions");
1621
1622 let info = consumer
1623 .consumer_running_info()
1624 .await
1625 .expect("running info facade should delegate to impl");
1626
1627 assert_eq!(
1628 info.properties
1629 .get(ConsumerRunningInfo::PROP_CONSUME_TYPE)
1630 .map(String::as_str),
1631 Some("CONSUME_PASSIVELY")
1632 );
1633 assert_eq!(
1634 info.properties
1635 .get(ConsumerRunningInfo::PROP_THREADPOOL_CORE_SIZE)
1636 .map(String::as_str),
1637 Some("7")
1638 );
1639 assert_eq!(info.properties.get("consumeThreadMax").map(String::as_str), Some("11"));
1640 assert_eq!(info.properties.get("pullBatchSize").map(String::as_str), Some("13"));
1641 assert!(info
1642 .subscription_set
1643 .iter()
1644 .any(|subscription| subscription.topic.as_str() == "TopicRunningInfo"
1645 && subscription.sub_string.as_str() == "TagA"));
1646 }
1647
1648 #[test]
1649 fn register_listener_without_impl_stores_listener_without_panic() {
1650 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1651 .consumer_group("push_missing_impl_group")
1652 .build();
1653 consumer.default_mqpush_consumer_impl = None;
1654
1655 consumer.register_message_listener_concurrently(TestConcurrentListener);
1656
1657 assert!(consumer.consumer_config_snapshot().message_listener.is_some());
1658 }
1659
1660 #[test]
1661 fn push_message_listener_facade_syncs_config_and_impl_like_java() {
1662 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1663 .consumer_group("push_listener_facade_group")
1664 .build();
1665 let listener = Arc::new(MessageListener::new(Some(Arc::new(TestConcurrentListener)), None));
1666
1667 assert!(consumer.default_mq_push_consumer_impl().is_some());
1668 assert!(consumer.message_listener().is_none());
1669
1670 consumer.set_message_listener(Some(listener.clone()));
1671
1672 let observed_listener = consumer.message_listener().expect("listener should be set");
1673 assert!(Arc::ptr_eq(&listener, &observed_listener));
1674 assert!(observed_listener.is_concurrently());
1675 assert!(consumer
1676 .consumer_config_snapshot()
1677 .message_listener
1678 .as_ref()
1679 .expect("config listener should be set")
1680 .is_concurrently());
1681
1682 consumer.register_message_listener_orderly(
1683 |_messages: &[&MessageExt], _context: &mut ConsumeOrderlyContext| Ok(ConsumeOrderlyStatus::Success),
1684 );
1685
1686 assert!(consumer
1687 .message_listener()
1688 .expect("orderly listener should replace concurrent listener")
1689 .is_orderly());
1690
1691 consumer.register_message_listener(None);
1692
1693 assert!(consumer.message_listener().is_none());
1694 assert!(consumer.consumer_config_snapshot().message_listener.is_none());
1695 }
1696
1697 #[test]
1698 fn push_subscription_facade_preserves_owned_snapshot_identity() {
1699 let consumer = DefaultMQPushConsumer::builder(test_runtime())
1700 .consumer_group("push_subscription_snapshot_group")
1701 .build();
1702 let first_snapshot = Arc::new(HashMap::from([(
1703 CheetahString::from_static_str("TopicSnapshot"),
1704 CheetahString::from_static_str("TagA"),
1705 )]));
1706
1707 consumer.update_consumer_config(|config| config.set_subscription(first_snapshot.clone()));
1708
1709 let observed = consumer.get_subscription();
1710 assert!(Arc::ptr_eq(&first_snapshot, &observed));
1711 assert_eq!(observed.get("TopicSnapshot").map(CheetahString::as_str), Some("TagA"));
1712
1713 let second_snapshot = Arc::new(HashMap::new());
1714 consumer.update_consumer_config(|config| config.set_subscription(second_snapshot.clone()));
1715
1716 assert!(Arc::ptr_eq(&second_snapshot, &consumer.get_subscription()));
1717 assert_eq!(
1718 first_snapshot.get("TopicSnapshot").map(CheetahString::as_str),
1719 Some("TagA")
1720 );
1721 }
1722
1723 #[test]
1724 fn push_use_tls_facade_updates_impl_config_like_java() {
1725 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1726 .consumer_group("push_tls_facade_group")
1727 .build();
1728
1729 assert!(!consumer.is_use_tls());
1730
1731 consumer.set_use_tls(true);
1732
1733 assert!(consumer.is_use_tls());
1734 let consumer_impl = consumer
1735 .default_mqpush_consumer_impl
1736 .as_ref()
1737 .expect("push consumer impl should exist");
1738 assert!(consumer_impl.client_config_snapshot().is_use_tls());
1739 assert!(consumer_impl.rebalance_impl.client_config_snapshot().is_use_tls());
1740 }
1741
1742 #[test]
1743 fn push_java_getter_aliases_delegate_to_config() {
1744 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1745 .consumer_group("push_java_getter_group")
1746 .build();
1747 let offset_store = Arc::new(OffsetStore::new_test());
1748
1749 consumer.set_message_model(MessageModel::Broadcasting);
1750 consumer.set_consume_from_where(ConsumeFromWhere::ConsumeFromFirstOffset);
1751 consumer.set_consume_timestamp("20260101000000");
1752 consumer.set_consume_thread_min(8);
1753 consumer.set_consume_thread_max(16);
1754 consumer.set_consume_concurrently_max_span(321);
1755 consumer.set_consume_message_batch_max_size(7);
1756 consumer.set_pull_batch_size(11);
1757 consumer.set_pull_interval(13);
1758 consumer.set_pull_threshold_for_queue(17);
1759 consumer.set_pull_threshold_for_topic(19);
1760 consumer.set_pull_threshold_size_for_queue(23);
1761 consumer.set_pull_threshold_size_for_topic(29);
1762 consumer.set_consume_timeout(31);
1763 consumer.set_offset_store(Some(offset_store));
1764
1765 assert!(consumer.get_allocate_message_queue_strategy().is_some());
1766 assert_eq!(consumer.get_message_model(), MessageModel::Broadcasting);
1767 assert_eq!(
1768 consumer.get_consume_from_where(),
1769 ConsumeFromWhere::ConsumeFromFirstOffset
1770 );
1771 assert_eq!(
1772 consumer.get_consume_timestamp(),
1773 Some(CheetahString::from_static_str("20260101000000"))
1774 );
1775 assert_eq!(consumer.get_consume_thread_min(), 8);
1776 assert_eq!(consumer.get_consume_thread_max(), 16);
1777 assert_eq!(consumer.get_consume_concurrently_max_span(), 321);
1778 assert_eq!(consumer.get_consume_message_batch_max_size(), 7);
1779 assert_eq!(consumer.get_pull_batch_size(), 11);
1780 assert_eq!(consumer.get_pull_interval(), 13);
1781 assert_eq!(consumer.get_pull_threshold_for_queue(), 17);
1782 assert_eq!(consumer.get_pull_threshold_for_topic(), 19);
1783 assert_eq!(consumer.get_pull_threshold_size_for_queue(), 23);
1784 assert_eq!(consumer.get_pull_threshold_size_for_topic(), 29);
1785 assert_eq!(consumer.get_consume_timeout(), 31);
1786 assert!(consumer.get_offset_store().is_some());
1787 assert!(consumer.get_subscription().is_empty());
1788 }
1789
1790 #[tokio::test]
1791 async fn push_offset_store_facade_updates_impl_like_java_start_source() {
1792 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1793 .consumer_group("push_offset_store_facade_group")
1794 .build();
1795 let offset_store = Arc::new(OffsetStore::new_test());
1796 let mq = MessageQueue::from_parts("TopicOffset", "broker-a", 0);
1797
1798 assert!(consumer.offset_store().is_none());
1799
1800 consumer.set_offset_store(Some(offset_store.clone()));
1801 offset_store.update_offset(&mq, 42, false).await;
1802
1803 assert_eq!(
1804 consumer
1805 .offset_store()
1806 .expect("facade offset store should be present")
1807 .read_offset(&mq, ReadOffsetType::ReadFromMemory)
1808 .await,
1809 42
1810 );
1811 assert_eq!(
1812 consumer
1813 .default_mqpush_consumer_impl
1814 .as_ref()
1815 .expect("push consumer impl should exist")
1816 .offset_store()
1817 .expect("impl offset store should be present")
1818 .read_offset(&mq, ReadOffsetType::ReadFromMemory)
1819 .await,
1820 42
1821 );
1822
1823 consumer.set_offset_store(None);
1824 assert!(consumer.offset_store().is_none());
1825 assert!(consumer
1826 .default_mqpush_consumer_impl
1827 .as_ref()
1828 .expect("push consumer impl should exist")
1829 .offset_store()
1830 .is_none());
1831 }
1832
1833 #[test]
1834 fn register_consume_message_hook_facade_updates_impl_like_java() {
1835 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1836 .consumer_group("push_hook_group")
1837 .build();
1838
1839 consumer
1840 .register_consume_message_hook(TestConsumeHook)
1841 .expect("hook registration should succeed");
1842
1843 assert_eq!(
1844 consumer
1845 .default_mqpush_consumer_impl
1846 .as_ref()
1847 .expect("push consumer impl should exist")
1848 .consume_message_hook_count(),
1849 1
1850 );
1851 }
1852
1853 #[test]
1854 fn register_consume_message_hook_without_impl_returns_typed_error() {
1855 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1856 .consumer_group("push_missing_impl_hook_group")
1857 .build();
1858 consumer.default_mqpush_consumer_impl = None;
1859
1860 let error = consumer
1861 .register_consume_message_hook(TestConsumeHook)
1862 .expect_err("hook registration without impl should fail");
1863
1864 assert_not_initialized(&error, "DefaultMQPushConsumerImpl");
1865 }
1866
1867 #[test]
1868 fn push_runtime_config_facade_updates_shared_impl_config_like_java() {
1869 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
1870 .consumer_group("push_runtime_config_group")
1871 .build();
1872 let initial_config = consumer.consumer_config_snapshot();
1873 let listener: ArcMessageQueueListener = Arc::new(TestMessageQueueListener);
1874
1875 consumer.set_allocate_message_queue_strategy(Arc::new(AllocateMessageQueueAveragely));
1876 consumer.set_consume_concurrently_max_span(1234);
1877 consumer.set_consume_from_where(ConsumeFromWhere::ConsumeFromFirstOffset);
1878 consumer.set_consume_message_batch_max_size(8);
1879 consumer.set_consumer_group("push_runtime_config_group_updated");
1880 consumer.set_consume_thread_max(48);
1881 consumer.set_consume_thread_min(12);
1882 consumer.set_message_model(MessageModel::Broadcasting);
1883 consumer.set_pull_batch_size(64);
1884 consumer.set_pull_interval(15);
1885 consumer.set_pull_threshold_for_queue(2048);
1886 consumer.set_pop_threshold_for_queue(128);
1887 consumer.set_pull_threshold_for_topic(4096);
1888 consumer.set_pull_threshold_size_for_queue(256);
1889 consumer.set_pull_threshold_size_for_topic(512);
1890 consumer.set_consume_timestamp("20260610101010");
1891 consumer.set_post_subscription_when_pull(true);
1892 consumer.set_unit_mode(true);
1893 consumer.set_adjust_thread_pool_nums_threshold(222_222);
1894 consumer.set_max_reconsume_times(19);
1895 consumer.set_suspend_current_queue_time_millis(3333);
1896 consumer.set_consume_timeout(44);
1897 consumer.set_pop_invisible_time(55_555);
1898 consumer.set_await_termination_millis_when_shutdown(66_666);
1899 consumer.set_pull_batch_size_in_bytes(512 * 1024);
1900 consumer.set_pop_batch_nums(16);
1901 consumer.set_client_rebalance(false);
1902 consumer.set_message_queue_listener(Some(listener));
1903
1904 assert_eq!(consumer.consume_concurrently_max_span(), 1234);
1905 assert_eq!(consumer.consume_from_where(), ConsumeFromWhere::ConsumeFromFirstOffset);
1906 assert_eq!(consumer.consume_message_batch_max_size(), 8);
1907 assert_eq!(consumer.consumer_group().as_str(), "push_runtime_config_group_updated");
1908 assert_eq!(consumer.consume_thread_max(), 48);
1909 assert_eq!(consumer.consume_thread_min(), 12);
1910 assert_eq!(consumer.message_model(), MessageModel::Broadcasting);
1911 assert_eq!(consumer.pull_batch_size(), 64);
1912 assert_eq!(consumer.pull_interval(), 15);
1913 assert_eq!(consumer.pull_threshold_for_queue(), 2048);
1914 assert_eq!(consumer.pop_threshold_for_queue(), 128);
1915 assert_eq!(consumer.pull_threshold_for_topic(), 4096);
1916 assert_eq!(consumer.pull_threshold_size_for_queue(), 256);
1917 assert_eq!(consumer.pull_threshold_size_for_topic(), 512);
1918 assert_eq!(
1919 consumer.consume_timestamp().as_ref().map(CheetahString::as_str),
1920 Some("20260610101010")
1921 );
1922 assert!(consumer.is_post_subscription_when_pull());
1923 assert!(consumer.is_unit_mode());
1924 assert_eq!(consumer.adjust_thread_pool_nums_threshold(), 222_222);
1925 assert_eq!(consumer.max_reconsume_times(), 19);
1926 assert_eq!(consumer.suspend_current_queue_time_millis(), 3333);
1927 assert_eq!(consumer.consume_timeout(), 44);
1928 assert_eq!(consumer.pop_invisible_time(), 55_555);
1929 assert_eq!(consumer.await_termination_millis_when_shutdown(), 66_666);
1930 assert_eq!(consumer.pull_batch_size_in_bytes(), 512 * 1024);
1931 assert_eq!(consumer.pop_batch_nums(), 16);
1932 assert!(!consumer.is_client_rebalance());
1933 assert!(consumer.message_queue_listener().is_some());
1934 assert!(consumer.allocate_message_queue_strategy().is_some());
1935
1936 let consumer_impl = consumer
1937 .default_mqpush_consumer_impl
1938 .as_ref()
1939 .expect("push consumer impl should exist");
1940 assert!(Arc::ptr_eq(&consumer.consumer_config, &consumer_impl.consumer_config));
1941 let impl_config = consumer_impl.consumer_config_snapshot();
1942 assert!(!Arc::ptr_eq(&initial_config, &impl_config));
1943 assert_eq!(initial_config.consumer_group.as_str(), "push_runtime_config_group");
1944 assert_eq!(initial_config.pull_batch_size, 32);
1945
1946 assert_eq!(impl_config.consume_concurrently_max_span, 1234);
1947 assert_eq!(impl_config.consume_from_where, ConsumeFromWhere::ConsumeFromFirstOffset);
1948 assert_eq!(impl_config.consume_message_batch_max_size, 8);
1949 assert_eq!(impl_config.consumer_group.as_str(), "push_runtime_config_group_updated");
1950 assert_eq!(impl_config.consume_thread_max, 48);
1951 assert_eq!(impl_config.consume_thread_min, 12);
1952 assert_eq!(impl_config.message_model, MessageModel::Broadcasting);
1953 assert_eq!(impl_config.pull_batch_size, 64);
1954 assert_eq!(impl_config.pull_interval, 15);
1955 assert_eq!(impl_config.pull_threshold_for_queue, 2048);
1956 assert_eq!(impl_config.pop_threshold_for_queue, 128);
1957 assert_eq!(impl_config.pull_threshold_for_topic, 4096);
1958 assert_eq!(impl_config.pull_threshold_size_for_queue, 256);
1959 assert_eq!(impl_config.pull_threshold_size_for_topic, 512);
1960 assert_eq!(
1961 impl_config.consume_timestamp.as_ref().map(CheetahString::as_str),
1962 Some("20260610101010")
1963 );
1964 assert!(impl_config.post_subscription_when_pull);
1965 assert!(impl_config.unit_mode);
1966 assert_eq!(impl_config.adjust_thread_pool_nums_threshold, 222_222);
1967 assert_eq!(impl_config.max_reconsume_times, 19);
1968 assert_eq!(impl_config.suspend_current_queue_time_millis, 3333);
1969 assert_eq!(impl_config.consume_timeout, 44);
1970 assert_eq!(impl_config.pop_invisible_time, 55_555);
1971 assert_eq!(impl_config.await_termination_millis_when_shutdown, 66_666);
1972 assert_eq!(impl_config.pull_batch_size_in_bytes, 512 * 1024);
1973 assert_eq!(impl_config.pop_batch_nums, 16);
1974 assert!(!impl_config.client_rebalance);
1975 assert!(impl_config.message_queue_listener.is_some());
1976
1977 let rebalance_config = consumer
1978 .default_mqpush_consumer_impl
1979 .as_ref()
1980 .expect("push consumer impl should exist")
1981 .rebalance_impl
1982 .consumer_config
1983 .load_full();
1984 assert_eq!(
1985 rebalance_config.consume_from_where,
1986 ConsumeFromWhere::ConsumeFromFirstOffset
1987 );
1988 assert_eq!(rebalance_config.message_model, MessageModel::Broadcasting);
1989 assert_eq!(rebalance_config.pull_threshold_for_queue, 2048);
1990 assert_eq!(rebalance_config.pull_threshold_for_topic, 4096);
1991 assert_eq!(rebalance_config.pull_threshold_size_for_queue, 256);
1992 assert_eq!(rebalance_config.pull_threshold_size_for_topic, 512);
1993 assert_eq!(
1994 rebalance_config.consume_timestamp.as_ref().map(CheetahString::as_str),
1995 Some("20260610101010")
1996 );
1997 assert!(!rebalance_config.client_rebalance);
1998 assert!(rebalance_config.message_queue_listener.is_some());
1999
2000 consumer.clear_consume_timestamp();
2001 assert!(consumer.consume_timestamp().is_none());
2002 assert!(consumer
2003 .default_mqpush_consumer_impl
2004 .as_ref()
2005 .expect("push consumer impl should exist")
2006 .rebalance_impl
2007 .consumer_config
2008 .load_full()
2009 .consume_timestamp
2010 .is_none());
2011 }
2012
2013 #[test]
2014 fn consumer_tuning_profile_keeps_defaults_until_applied() {
2015 let config = ConsumerConfig::default();
2016
2017 assert_eq!(config.consume_message_batch_max_size(), 1);
2018 assert_eq!(config.pull_batch_size(), 32);
2019 assert_eq!(config.pull_batch_size_in_bytes(), 256 * 1024);
2020 assert_eq!(config.pull_threshold_for_queue(), 1000);
2021 assert_eq!(config.pull_threshold_size_for_queue(), 100);
2022 assert_eq!(config.pull_interval(), 0);
2023 }
2024
2025 #[test]
2026 fn consumer_tuning_profiles_apply_expected_values() {
2027 let mut config = ConsumerConfig::default();
2028
2029 config.apply_tuning_profile(ConsumerTuningProfile::Throughput);
2030 assert_eq!(config.consume_message_batch_max_size(), 16);
2031 assert_eq!(config.pull_batch_size(), 128);
2032 assert_eq!(config.pull_batch_size_in_bytes(), 1024 * 1024);
2033 assert_eq!(config.pull_threshold_for_queue(), 4096);
2034 assert_eq!(config.pull_threshold_size_for_queue(), 256);
2035 assert_eq!(config.pull_interval(), 0);
2036
2037 config.apply_tuning_profile(ConsumerTuningProfile::LargeMessage);
2038 assert_eq!(config.consume_message_batch_max_size(), 1);
2039 assert_eq!(config.pull_batch_size(), 8);
2040 assert_eq!(config.pull_batch_size_in_bytes(), 512 * 1024);
2041 assert_eq!(config.pull_threshold_for_queue(), 128);
2042 assert_eq!(config.pull_threshold_size_for_queue(), 64);
2043
2044 config.apply_tuning_profile(ConsumerTuningProfile::SlowListener);
2045 assert_eq!(config.consume_message_batch_max_size(), 1);
2046 assert_eq!(config.pull_batch_size(), 16);
2047 assert_eq!(config.pull_threshold_for_queue(), 100);
2048 assert_eq!(config.pull_threshold_size_for_queue(), 16);
2049 assert_eq!(config.pull_interval(), 50);
2050
2051 config.apply_tuning_profile(ConsumerTuningProfile::LowLatency);
2052 assert_eq!(config.consume_message_batch_max_size(), 1);
2053 assert_eq!(config.pull_batch_size(), 16);
2054 assert_eq!(config.pull_batch_size_in_bytes(), 256 * 1024);
2055 assert_eq!(config.pull_threshold_for_queue(), 256);
2056 assert_eq!(config.pull_threshold_size_for_queue(), 32);
2057 assert_eq!(config.pull_interval(), 0);
2058 }
2059
2060 #[test]
2061 fn push_consumer_apply_tuning_profile_updates_shared_impl_config() {
2062 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
2063 .consumer_group("push_profile_runtime_group")
2064 .build();
2065
2066 consumer.apply_tuning_profile(ConsumerTuningProfile::Throughput);
2067
2068 assert_eq!(consumer.consume_message_batch_max_size(), 16);
2069 assert_eq!(consumer.pull_batch_size(), 128);
2070 assert_eq!(consumer.pull_batch_size_in_bytes(), 1024 * 1024);
2071 assert_eq!(consumer.pull_threshold_for_queue(), 4096);
2072 assert_eq!(consumer.pull_threshold_size_for_queue(), 256);
2073
2074 let impl_config = consumer
2075 .default_mqpush_consumer_impl
2076 .as_ref()
2077 .expect("push consumer impl should exist")
2078 .consumer_config_snapshot();
2079
2080 assert_eq!(impl_config.consume_message_batch_max_size, 16);
2081 assert_eq!(impl_config.pull_batch_size, 128);
2082 assert_eq!(impl_config.pull_batch_size_in_bytes, 1024 * 1024);
2083 assert_eq!(impl_config.pull_threshold_for_queue, 4096);
2084 assert_eq!(impl_config.pull_threshold_size_for_queue, 256);
2085 }
2086
2087 #[tokio::test]
2088 async fn push_pause_state_facade_matches_impl_like_java() {
2089 let consumer = DefaultMQPushConsumer::builder(test_runtime())
2090 .consumer_group("push_pause_state_group")
2091 .build();
2092
2093 assert!(!consumer.is_pause());
2094 consumer.suspend().await;
2095 assert!(consumer.is_pause());
2096 consumer.resume().await;
2097 assert!(!consumer.is_pause());
2098 }
2099
2100 #[test]
2101 fn is_consume_orderly_facade_reflects_impl_state_like_java() {
2102 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
2103 .consumer_group("push_orderly_state_group")
2104 .build();
2105
2106 assert!(!consumer.is_consume_orderly());
2107
2108 consumer
2109 .default_mqpush_consumer_impl
2110 .as_mut()
2111 .expect("push consumer impl should exist")
2112 .set_consume_orderly(true);
2113
2114 assert!(consumer.is_consume_orderly());
2115 }
2116
2117 #[tokio::test]
2118 async fn push_facade_namespace_subscribe_wraps_topic_like_java() {
2119 let mut consumer = namespaced_push_consumer();
2120
2121 consumer
2122 .subscribe("TopicA", "TagA")
2123 .await
2124 .expect("subscribe should succeed before start");
2125
2126 let subscriptions = consumer
2127 .default_mqpush_consumer_impl
2128 .as_ref()
2129 .expect("push consumer impl should exist")
2130 .subscriptions();
2131 let subscription = subscriptions
2132 .iter()
2133 .find(|subscription| subscription.topic.as_str() == "ns%TopicA")
2134 .expect("namespaced topic should be subscribed");
2135 assert_eq!(subscription.sub_string.as_str(), "TagA");
2136 assert!(!subscriptions
2137 .iter()
2138 .any(|subscription| subscription.topic.as_str() == "TopicA"));
2139 }
2140
2141 #[tokio::test]
2142 async fn push_facade_namespace_selector_subscribe_wraps_topic_like_java() {
2143 let mut consumer = namespaced_push_consumer();
2144
2145 consumer
2146 .subscribe_with_selector("TopicB", Some(MessageSelector::by_tag("TagB")))
2147 .await
2148 .expect("selector subscribe should succeed before start");
2149
2150 let subscriptions = consumer
2151 .default_mqpush_consumer_impl
2152 .as_ref()
2153 .expect("push consumer impl should exist")
2154 .subscriptions();
2155 let subscription = subscriptions
2156 .iter()
2157 .find(|subscription| subscription.topic.as_str() == "ns%TopicB")
2158 .expect("namespaced selector topic should be subscribed");
2159 assert_eq!(subscription.sub_string.as_str(), "TagB");
2160 assert!(!subscriptions
2161 .iter()
2162 .any(|subscription| subscription.topic.as_str() == "TopicB"));
2163 }
2164
2165 #[tokio::test]
2166 async fn push_facade_namespace_unsubscribe_passes_topic_through_like_java() {
2167 let mut consumer = namespaced_push_consumer();
2168 consumer
2169 .subscribe("TopicC", "*")
2170 .await
2171 .expect("subscribe should succeed before start");
2172
2173 consumer.unsubscribe("TopicC").await;
2174
2175 let subscriptions = consumer
2176 .default_mqpush_consumer_impl
2177 .as_ref()
2178 .expect("push consumer impl should exist")
2179 .subscriptions();
2180 assert!(subscriptions
2181 .iter()
2182 .any(|subscription| subscription.topic.as_str() == "ns%TopicC"));
2183
2184 consumer.unsubscribe("ns%TopicC").await;
2185
2186 let subscriptions = consumer
2187 .default_mqpush_consumer_impl
2188 .as_ref()
2189 .expect("push consumer impl should exist")
2190 .subscriptions();
2191 assert!(!subscriptions
2192 .iter()
2193 .any(|subscription| subscription.topic.as_str() == "ns%TopicC"));
2194 }
2195
2196 #[tokio::test]
2197 async fn custom_trace_dispatcher_registers_hook_and_starts_with_client_config() {
2198 let dispatcher = Arc::new(CapturingTraceDispatcher::default());
2199 let trace_dispatcher: ArcTraceDispatcher = dispatcher.clone();
2200 let mut client_config = ClientConfig::default();
2201 client_config.set_namesrv_addr(CheetahString::from_static_str("127.0.0.1:9876"));
2202 client_config.set_access_channel(AccessChannel::Cloud);
2203
2204 let mut consumer = DefaultMQPushConsumer::builder(test_runtime())
2205 .consumer_group("push_trace_group")
2206 .client_config(client_config)
2207 .trace_dispatcher(Some(trace_dispatcher))
2208 .build();
2209
2210 let trace_dispatcher_to_start = {
2211 let consumer_config = consumer.consumer_config.clone();
2212 let consumer_impl = consumer
2213 .default_mqpush_consumer_impl
2214 .as_mut()
2215 .expect("push consumer impl should exist");
2216 DefaultMQPushConsumer::prepare_trace_dispatcher(
2217 &consumer.client_runtime,
2218 &consumer.client_config,
2219 &consumer_config,
2220 consumer_impl,
2221 )
2222 .expect("custom dispatcher should be prepared")
2223 };
2224
2225 assert_eq!(
2226 consumer
2227 .default_mqpush_consumer_impl
2228 .as_ref()
2229 .expect("push consumer impl should exist")
2230 .consume_message_hook_count(),
2231 1
2232 );
2233
2234 consumer.start_trace_dispatcher(trace_dispatcher_to_start).await;
2235 assert_eq!(dispatcher.start_count.load(Ordering::SeqCst), 1);
2236 assert_eq!(
2237 dispatcher
2238 .last_name_srv_addr
2239 .lock()
2240 .expect("name server lock")
2241 .as_deref(),
2242 Some("127.0.0.1:9876")
2243 );
2244 assert_eq!(
2245 *dispatcher.last_access_channel.lock().expect("access channel lock"),
2246 Some(AccessChannel::Cloud)
2247 );
2248 }
2249}