Skip to main content

rocketmq_client_rust/consumer/
default_mq_push_consumer.rs

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