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 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    //this field will be removed in a certain version after April 5, 2020
72    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 message_listener(&self) -> &Option<Arc<MessageListener>> {
128        &self.message_listener
129    }*/
130
131    /*    pub fn message_queue_listener(&self) -> &Option<ArcMessageQueueListener> {
132        &self.message_queue_listener
133    }*/
134
135    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    /**
296     * This method will be removed in a certain version after April 5, 2020, so please do not
297     * use this method.
298     */
299    pub fn set_subscription(&mut self, subscription: Arc<HashMap<CheetahString, CheetahString>>) {
300        self.subscription = subscription;
301    }
302
303    /*    pub fn set_message_listener(
304        &mut self,
305        message_listener: Option<Arc<MessageListener>>,
306    ) {
307        self.message_listener = message_listener;
308    }*/
309
310    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    /// Returns a Java-compatible running snapshot for broker admin diagnostics.
854    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    /// Returns whether this push consumer is currently paused.
918    ///
919    /// Mirrors Java `DefaultMQPushConsumer.isPause`.
920    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    /// Returns whether the registered listener consumes messages orderly.
927    ///
928    /// Mirrors Java `DefaultMQPushConsumer.isConsumeOrderly`.
929    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    /// Registers a hook invoked before and after message consumption.
936    ///
937    /// Mirrors Java `DefaultMQPushConsumer.registerConsumeMessageHook`.
938    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}