1use std::collections::HashMap;
16use std::collections::HashSet;
17use std::sync::Arc;
18use std::sync::RwLock as StdRwLock;
19
20use crate::ClientError;
21use crate::ClientResult;
22use arc_swap::ArcSwap;
23use cheetah_string::CheetahString;
24use rocketmq_model::common::consumer::consume_from_where::ConsumeFromWhere;
25use rocketmq_model::common::message::message_ext::MessageExt;
26use rocketmq_model::common::message::message_queue::MessageQueue;
27use rocketmq_model::common::topic::TopicValidator;
28use rocketmq_protocol::common::message::message_decoder as MessageDecoder;
29use rocketmq_protocol::protocol::body::consumer_running_info::ConsumerRunningInfo;
30use rocketmq_protocol::protocol::heartbeat::message_model::MessageModel;
31use rocketmq_protocol::protocol::heartbeat::subscription_data::SubscriptionData;
32use rocketmq_protocol::protocol::namespace_util::NamespaceUtil;
33use rocketmq_transport::api::RPCHook;
34use tokio::sync::OnceCell;
35use tokio::sync::RwLock;
36
37use crate::base::client_config::ClientConfig;
38use crate::base::client_options::ClientOptions;
39use crate::base::query_result::QueryResult;
40use crate::consumer::allocate_message_queue_strategy::AllocateMessageQueueStrategy;
41use crate::consumer::consumer_impl::default_lite_pull_consumer_impl::validate_lite_pull_consume_from_where;
42use crate::consumer::consumer_impl::default_lite_pull_consumer_impl::DefaultLitePullConsumerImpl;
43use crate::consumer::consumer_impl::default_lite_pull_consumer_impl::LitePullConsumerConfig;
44use crate::consumer::default_lite_pull_consumer_builder::DefaultLitePullConsumerBuilder;
45use crate::consumer::default_lite_pull_consumer_builder::MIN_AUTOCOMMIT_INTERVAL_MILLIS;
46use crate::consumer::lite_pull_consumer::{
47 AssignmentControl, ConsumerLifecycle, ConsumerOffsetControl, MessagePoll, SubscriptionControl,
48};
49use crate::consumer::message_queue_listener::ArcMessageQueueListener;
50use crate::consumer::message_queue_listener::MessageQueueListener;
51use crate::consumer::message_selector::MessageSelector;
52use crate::consumer::mq_consumer::MQConsumer;
53use crate::consumer::mq_consumer_inner::MQConsumerInner;
54use crate::consumer::store::offset_store::OffsetStore;
55use crate::consumer::topic_message_queue_change_listener::TopicMessageQueueChangeListener;
56use crate::nameserver_discovery::NameServerDiscoveryConfig;
57use crate::runtime::ClientRuntime;
58use crate::session::ClientSession;
59use crate::session::ClientSessionProvider;
60use crate::trace::async_trace_dispatcher::AsyncTraceDispatcher;
61use crate::trace::hook::consume_message_trace_hook_impl::ConsumeMessageTraceHookImpl;
62use crate::trace::trace_dispatcher::TraceDispatcher;
63use crate::trace::trace_dispatcher::Type;
64
65#[derive(Clone)]
152pub struct DefaultLitePullConsumer {
153 session: ClientSession,
154 client_config: Arc<ArcSwap<ClientConfig>>,
156 nameserver_discovery: Option<NameServerDiscoveryConfig>,
157
158 consumer_config: Arc<ArcSwap<LitePullConsumerConfig>>,
160
161 default_lite_pull_consumer_impl: Arc<OnceCell<Arc<DefaultLitePullConsumerImpl>>>,
163
164 rpc_hook: Option<Arc<dyn RPCHook>>,
166
167 trace_dispatcher: Arc<RwLock<Option<Arc<dyn TraceDispatcher + Send + Sync>>>>,
169
170 enable_msg_trace: bool,
172
173 custom_trace_topic: Option<CheetahString>,
175
176 message_queue_listener: Arc<StdRwLock<Option<ArcMessageQueueListener>>>,
178
179 offset_store: Arc<StdRwLock<Option<Arc<OffsetStore>>>>,
181}
182
183impl DefaultLitePullConsumer {
184 pub fn new(
188 client_runtime: Arc<ClientRuntime>,
189 client_config: ClientConfig,
190 consumer_config: LitePullConsumerConfig,
191 rpc_hook: Option<Arc<dyn RPCHook>>,
192 trace_dispatcher: Option<Arc<dyn TraceDispatcher + Send + Sync>>,
193 enable_msg_trace: bool,
194 custom_trace_topic: Option<CheetahString>,
195 ) -> Self {
196 Self::new_with_options(
197 client_runtime,
198 ClientOptions::legacy(client_config),
199 consumer_config,
200 rpc_hook,
201 trace_dispatcher,
202 enable_msg_trace,
203 custom_trace_topic,
204 )
205 }
206
207 pub(crate) fn new_with_options(
208 client_runtime: Arc<ClientRuntime>,
209 options: ClientOptions,
210 consumer_config: LitePullConsumerConfig,
211 rpc_hook: Option<Arc<dyn RPCHook>>,
212 trace_dispatcher: Option<Arc<dyn TraceDispatcher + Send + Sync>>,
213 enable_msg_trace: bool,
214 custom_trace_topic: Option<CheetahString>,
215 ) -> Self {
216 Self {
217 session: ClientSession::new(client_runtime),
218 client_config: Arc::new(ArcSwap::from_pointee(options.client_config().clone())),
219 nameserver_discovery: options.nameserver_discovery().cloned(),
220 consumer_config: Arc::new(ArcSwap::from_pointee(consumer_config)),
221 default_lite_pull_consumer_impl: Arc::new(OnceCell::new()),
222 rpc_hook,
223 trace_dispatcher: Arc::new(RwLock::new(trace_dispatcher)),
224 enable_msg_trace,
225 custom_trace_topic,
226 message_queue_listener: Arc::new(StdRwLock::new(None)),
227 offset_store: Arc::new(StdRwLock::new(None)),
228 }
229 }
230
231 fn client_config_snapshot(&self) -> Arc<ClientConfig> {
232 self.client_config.load_full()
233 }
234
235 fn consumer_config_snapshot(&self) -> Arc<LitePullConsumerConfig> {
236 self.consumer_config.load_full()
237 }
238
239 fn update_client_config(&self, update: impl Fn(&mut ClientConfig)) {
240 self.client_config.rcu(|current| {
241 let mut next = (**current).clone();
242 update(&mut next);
243 Arc::new(next)
244 });
245 }
246
247 fn update_consumer_config(&self, update: impl Fn(&mut LitePullConsumerConfig)) {
248 self.consumer_config.rcu(|current| {
249 let mut next = (**current).clone();
250 update(&mut next);
251 Arc::new(next)
252 });
253 }
254
255 pub fn builder(client_runtime: Arc<ClientRuntime>) -> DefaultLitePullConsumerBuilder {
267 DefaultLitePullConsumerBuilder::new(client_runtime)
268 }
269
270 pub async fn start(&self) -> ClientResult<()> {
272 <Self as ConsumerLifecycle>::start(self).await
273 }
274
275 pub async fn shutdown(&self) {
277 <Self as ConsumerLifecycle>::shutdown(self).await;
278 }
279
280 pub async fn is_running(&self) -> bool {
282 <Self as ConsumerLifecycle>::is_running(self).await
283 }
284
285 pub async fn consumer_running_info(&self) -> ClientResult<ConsumerRunningInfo> {
287 let impl_ = self.try_impl_()?;
288 Ok(MQConsumerInner::consumer_running_info(impl_.as_ref()).await)
289 }
290
291 pub async fn subscribe(&self, topic: &str) -> ClientResult<()> {
293 <Self as SubscriptionControl>::subscribe(self, topic).await
294 }
295
296 pub async fn subscribe_with_expression(&self, topic: &str, sub_expression: &str) -> ClientResult<()> {
298 <Self as SubscriptionControl>::subscribe_with_expression(self, topic, sub_expression).await
299 }
300
301 pub async fn subscribe_with_listener<MQL>(
303 &self,
304 topic: &str,
305 sub_expression: &str,
306 listener: MQL,
307 ) -> ClientResult<()>
308 where
309 MQL: MessageQueueListener + 'static,
310 {
311 <Self as SubscriptionControl>::subscribe_with_listener(self, topic, sub_expression, listener).await
312 }
313
314 pub async fn subscribe_with_selector(&self, topic: &str, selector: Option<MessageSelector>) -> ClientResult<()> {
316 <Self as SubscriptionControl>::subscribe_with_selector(self, topic, selector).await
317 }
318
319 pub async fn unsubscribe(&self, topic: &str) {
321 <Self as SubscriptionControl>::unsubscribe(self, topic).await;
322 }
323
324 pub async fn assignment(&self) -> ClientResult<HashSet<MessageQueue>> {
326 <Self as AssignmentControl>::assignment(self).await
327 }
328
329 pub async fn assign(&self, message_queues: Vec<MessageQueue>) -> ClientResult<()> {
331 <Self as AssignmentControl>::assign(self, message_queues).await
332 }
333
334 pub async fn set_sub_expression_for_assign(&self, topic: &str, sub_expression: &str) -> ClientResult<()> {
336 <Self as AssignmentControl>::set_sub_expression_for_assign(self, topic, sub_expression).await
337 }
338
339 pub async fn build_subscriptions_for_heartbeat(
341 &self,
342 sub_expression_map: &mut HashMap<String, MessageSelector>,
343 ) -> ClientResult<()> {
344 <Self as SubscriptionControl>::build_subscriptions_for_heartbeat(self, sub_expression_map).await
345 }
346
347 pub async fn subscriptions_for_heartbeat(&self) -> HashSet<SubscriptionData> {
349 <Self as SubscriptionControl>::subscriptions_for_heartbeat(self).await
350 }
351
352 pub async fn get_subscriptions_for_heartbeat(&self) -> HashSet<SubscriptionData> {
354 self.subscriptions_for_heartbeat().await
355 }
356
357 pub async fn poll_zero_copy(&self) -> Vec<Arc<MessageExt>> {
359 <Self as MessagePoll>::poll_zero_copy(self).await
360 }
361
362 pub async fn poll_with_timeout_zero_copy(&self, timeout: u64) -> Vec<Arc<MessageExt>> {
364 <Self as MessagePoll>::poll_with_timeout_zero_copy(self, timeout).await
365 }
366
367 pub async fn poll(&self) -> Vec<MessageExt> {
369 <Self as MessagePoll>::poll(self).await
370 }
371
372 pub async fn poll_with_timeout(&self, timeout: u64) -> Vec<MessageExt> {
374 <Self as MessagePoll>::poll_with_timeout(self, timeout).await
375 }
376
377 pub async fn message_model(&self) -> MessageModel {
379 <Self as SubscriptionControl>::message_model(self).await
380 }
381
382 pub async fn get_message_model(&self) -> MessageModel {
384 self.message_model().await
385 }
386
387 pub async fn set_message_model(&self, message_model: MessageModel) {
389 <Self as SubscriptionControl>::set_message_model(self, message_model).await;
390 }
391
392 pub async fn consume_from_where(&self) -> ConsumeFromWhere {
394 <Self as SubscriptionControl>::consume_from_where(self).await
395 }
396
397 pub async fn get_consume_from_where(&self) -> ConsumeFromWhere {
399 self.consume_from_where().await
400 }
401
402 pub async fn set_consume_from_where(&self, consume_from_where: ConsumeFromWhere) -> ClientResult<()> {
404 <Self as SubscriptionControl>::set_consume_from_where(self, consume_from_where).await
405 }
406
407 pub async fn consume_timestamp(&self) -> Option<CheetahString> {
409 <Self as SubscriptionControl>::consume_timestamp(self).await
410 }
411
412 pub async fn get_consume_timestamp(&self) -> Option<CheetahString> {
414 self.consume_timestamp().await
415 }
416
417 pub async fn set_consume_timestamp(&self, consume_timestamp: Option<CheetahString>) {
419 <Self as SubscriptionControl>::set_consume_timestamp(self, consume_timestamp).await;
420 }
421
422 pub async fn allocate_message_queue_strategy(&self) -> Arc<dyn AllocateMessageQueueStrategy + Send + Sync> {
424 <Self as SubscriptionControl>::allocate_message_queue_strategy(self).await
425 }
426
427 pub async fn get_allocate_message_queue_strategy(&self) -> Arc<dyn AllocateMessageQueueStrategy + Send + Sync> {
429 self.allocate_message_queue_strategy().await
430 }
431
432 pub async fn set_allocate_message_queue_strategy(
434 &self,
435 allocate_message_queue_strategy: Arc<dyn AllocateMessageQueueStrategy + Send + Sync>,
436 ) {
437 <Self as SubscriptionControl>::set_allocate_message_queue_strategy(self, allocate_message_queue_strategy).await;
438 }
439
440 pub async fn message_queue_listener(&self) -> Option<ArcMessageQueueListener> {
442 <Self as SubscriptionControl>::message_queue_listener(self).await
443 }
444
445 pub async fn get_message_queue_listener(&self) -> Option<ArcMessageQueueListener> {
447 self.message_queue_listener().await
448 }
449
450 pub async fn set_message_queue_listener(&self, message_queue_listener: Option<ArcMessageQueueListener>) {
452 <Self as SubscriptionControl>::set_message_queue_listener(self, message_queue_listener).await;
453 }
454
455 pub async fn offset_store(&self) -> Option<Arc<OffsetStore>> {
457 <Self as ConsumerOffsetControl>::offset_store(self).await
458 }
459
460 pub async fn get_offset_store(&self) -> Option<Arc<OffsetStore>> {
462 self.offset_store().await
463 }
464
465 pub async fn set_offset_store(&self, offset_store: Option<Arc<OffsetStore>>) -> ClientResult<()> {
467 <Self as ConsumerOffsetControl>::set_offset_store(self, offset_store).await
468 }
469
470 pub async fn topic_metadata_check_interval_millis(&self) -> u64 {
472 <Self as SubscriptionControl>::topic_metadata_check_interval_millis(self).await
473 }
474
475 pub async fn get_topic_metadata_check_interval_millis(&self) -> u64 {
477 self.topic_metadata_check_interval_millis().await
478 }
479
480 pub async fn set_topic_metadata_check_interval_millis(&self, interval_millis: u64) {
482 <Self as SubscriptionControl>::set_topic_metadata_check_interval_millis(self, interval_millis).await;
483 }
484
485 pub async fn poll_timeout_millis(&self) -> u64 {
487 <Self as MessagePoll>::poll_timeout_millis(self).await
488 }
489
490 pub async fn get_poll_timeout_millis(&self) -> u64 {
492 self.poll_timeout_millis().await
493 }
494
495 pub async fn set_poll_timeout_millis(&self, timeout_millis: u64) {
497 <Self as MessagePoll>::set_poll_timeout_millis(self, timeout_millis).await;
498 }
499
500 pub async fn broker_suspend_max_time_millis(&self) -> u64 {
502 <Self as MessagePoll>::broker_suspend_max_time_millis(self).await
503 }
504
505 pub async fn get_broker_suspend_max_time_millis(&self) -> u64 {
507 self.broker_suspend_max_time_millis().await
508 }
509
510 pub async fn set_broker_suspend_max_time_millis(&self, timeout_millis: u64) {
512 <Self as MessagePoll>::set_broker_suspend_max_time_millis(self, timeout_millis).await;
513 }
514
515 pub async fn consumer_timeout_millis_when_suspend(&self) -> u64 {
517 <Self as MessagePoll>::consumer_timeout_millis_when_suspend(self).await
518 }
519
520 pub async fn get_consumer_timeout_millis_when_suspend(&self) -> u64 {
522 self.consumer_timeout_millis_when_suspend().await
523 }
524
525 pub async fn set_consumer_timeout_millis_when_suspend(&self, timeout_millis: u64) {
527 <Self as MessagePoll>::set_consumer_timeout_millis_when_suspend(self, timeout_millis).await;
528 }
529
530 pub async fn consumer_pull_timeout_millis(&self) -> u64 {
532 <Self as MessagePoll>::consumer_pull_timeout_millis(self).await
533 }
534
535 pub async fn get_consumer_pull_timeout_millis(&self) -> u64 {
537 self.consumer_pull_timeout_millis().await
538 }
539
540 pub async fn set_consumer_pull_timeout_millis(&self, timeout_millis: u64) {
542 <Self as MessagePoll>::set_consumer_pull_timeout_millis(self, timeout_millis).await;
543 }
544
545 pub async fn pull_batch_size(&self) -> i32 {
547 <Self as MessagePoll>::pull_batch_size(self).await
548 }
549
550 pub async fn get_pull_batch_size(&self) -> i32 {
552 self.pull_batch_size().await
553 }
554
555 pub async fn set_pull_batch_size(&self, pull_batch_size: i32) {
557 <Self as MessagePoll>::set_pull_batch_size(self, pull_batch_size).await;
558 }
559
560 pub async fn pull_thread_nums(&self) -> usize {
562 <Self as MessagePoll>::pull_thread_nums(self).await
563 }
564
565 pub async fn get_pull_thread_nums(&self) -> usize {
567 self.pull_thread_nums().await
568 }
569
570 pub async fn set_pull_thread_nums(&self, pull_thread_nums: usize) {
572 <Self as MessagePoll>::set_pull_thread_nums(self, pull_thread_nums).await;
573 }
574
575 pub async fn try_set_pull_thread_nums(&self, pull_thread_nums: usize) -> ClientResult<()> {
582 if pull_thread_nums == 0 {
583 return Err(crate::mq_client_err!("pullThreadNums must be greater than 0"));
584 }
585 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
586 impl_.try_set_pull_thread_nums(pull_thread_nums)?;
587 }
588 self.update_consumer_config(|config| config.pull_thread_nums = pull_thread_nums);
589 Ok(())
590 }
591
592 pub async fn pull_threshold_for_all(&self) -> i64 {
594 <Self as MessagePoll>::pull_threshold_for_all(self).await
595 }
596
597 pub async fn get_pull_threshold_for_all(&self) -> i64 {
599 self.pull_threshold_for_all().await
600 }
601
602 pub async fn set_pull_threshold_for_all(&self, pull_threshold_for_all: i64) {
604 <Self as MessagePoll>::set_pull_threshold_for_all(self, pull_threshold_for_all).await;
605 }
606
607 pub async fn pull_threshold_for_queue(&self) -> i64 {
609 <Self as MessagePoll>::pull_threshold_for_queue(self).await
610 }
611
612 pub async fn get_pull_threshold_for_queue(&self) -> i64 {
614 self.pull_threshold_for_queue().await
615 }
616
617 pub async fn set_pull_threshold_for_queue(&self, pull_threshold_for_queue: i64) {
619 <Self as MessagePoll>::set_pull_threshold_for_queue(self, pull_threshold_for_queue).await;
620 }
621
622 pub async fn pull_threshold_size_for_queue(&self) -> i32 {
624 <Self as MessagePoll>::pull_threshold_size_for_queue(self).await
625 }
626
627 pub async fn get_pull_threshold_size_for_queue(&self) -> i32 {
629 self.pull_threshold_size_for_queue().await
630 }
631
632 pub async fn set_pull_threshold_size_for_queue(&self, pull_threshold_size_for_queue: i32) {
634 <Self as MessagePoll>::set_pull_threshold_size_for_queue(self, pull_threshold_size_for_queue).await;
635 }
636
637 pub async fn consume_max_span(&self) -> i64 {
639 <Self as MessagePoll>::consume_max_span(self).await
640 }
641
642 pub async fn get_consume_max_span(&self) -> i64 {
644 self.consume_max_span().await
645 }
646
647 pub async fn set_consume_max_span(&self, consume_max_span: i64) {
649 <Self as MessagePoll>::set_consume_max_span(self, consume_max_span).await;
650 }
651
652 pub async fn is_connect_broker_by_user(&self) -> bool {
654 <Self as SubscriptionControl>::is_connect_broker_by_user(self).await
655 }
656
657 pub async fn set_connect_broker_by_user(&self, connect_broker_by_user: bool) {
659 <Self as SubscriptionControl>::set_connect_broker_by_user(self, connect_broker_by_user).await;
660 }
661
662 pub async fn default_broker_id(&self) -> u64 {
664 <Self as SubscriptionControl>::default_broker_id(self).await
665 }
666
667 pub async fn get_default_broker_id(&self) -> u64 {
669 self.default_broker_id().await
670 }
671
672 pub async fn set_default_broker_id(&self, broker_id: u64) {
674 <Self as SubscriptionControl>::set_default_broker_id(self, broker_id).await;
675 }
676
677 pub async fn fetch_message_queues(&self, topic: &str) -> ClientResult<Vec<MessageQueue>> {
679 <Self as ConsumerOffsetControl>::fetch_message_queues(self, topic).await
680 }
681
682 pub async fn committed(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
684 <Self as ConsumerOffsetControl>::committed(self, message_queue).await
685 }
686
687 pub async fn commit_all(&self) -> ClientResult<()> {
689 <Self as ConsumerOffsetControl>::commit_all(self).await
690 }
691
692 pub async fn commit_with_map(&self, offset_map: HashMap<MessageQueue, i64>, persist: bool) {
694 <Self as ConsumerOffsetControl>::commit_with_map(self, offset_map, persist).await;
695 }
696
697 pub async fn commit(&self) {
699 <Self as ConsumerOffsetControl>::commit(self).await;
700 }
701
702 pub async fn commit_with_set(&self, message_queues: HashSet<MessageQueue>, persist: bool) {
704 <Self as ConsumerOffsetControl>::commit_with_set(self, message_queues, persist).await;
705 }
706
707 pub async fn commit_sync(&self) {
709 <Self as ConsumerOffsetControl>::commit_sync(self).await;
710 }
711
712 pub async fn commit_sync_with_map(&self, offset_map: HashMap<MessageQueue, i64>, persist: bool) {
714 <Self as ConsumerOffsetControl>::commit_sync_with_map(self, offset_map, persist).await;
715 }
716
717 pub async fn is_auto_commit(&self) -> bool {
719 <Self as ConsumerOffsetControl>::is_auto_commit(self).await
720 }
721
722 pub async fn set_auto_commit(&self, auto_commit: bool) {
724 <Self as ConsumerOffsetControl>::set_auto_commit(self, auto_commit).await;
725 }
726
727 pub async fn is_unit_mode(&self) -> bool {
729 <Self as SubscriptionControl>::is_unit_mode(self).await
730 }
731
732 pub async fn set_unit_mode(&self, unit_mode: bool) {
734 <Self as SubscriptionControl>::set_unit_mode(self, unit_mode).await;
735 }
736
737 pub async fn auto_commit_interval_millis(&self) -> u64 {
739 <Self as ConsumerOffsetControl>::auto_commit_interval_millis(self).await
740 }
741
742 pub async fn get_auto_commit_interval_millis(&self) -> u64 {
744 self.auto_commit_interval_millis().await
745 }
746
747 pub async fn set_auto_commit_interval_millis(&self, interval_millis: u64) {
749 <Self as ConsumerOffsetControl>::set_auto_commit_interval_millis(self, interval_millis).await;
750 }
751
752 pub async fn offset_for_timestamp(&self, message_queue: &MessageQueue, timestamp: u64) -> ClientResult<i64> {
754 <Self as ConsumerOffsetControl>::offset_for_timestamp(self, message_queue, timestamp).await
755 }
756
757 pub async fn earliest_msg_store_time(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
759 <Self as ConsumerOffsetControl>::earliest_msg_store_time(self, message_queue).await
760 }
761
762 pub async fn max_offset(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
764 <Self as ConsumerOffsetControl>::max_offset(self, message_queue).await
765 }
766
767 pub async fn min_offset(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
769 <Self as ConsumerOffsetControl>::min_offset(self, message_queue).await
770 }
771
772 pub async fn create_topic(
774 &self,
775 key: &str,
776 new_topic: &str,
777 queue_num: i32,
778 attributes: HashMap<String, String>,
779 ) -> ClientResult<()> {
780 self.create_topic_with_flag(key, new_topic, queue_num, 0, attributes)
781 .await
782 }
783
784 pub async fn create_topic_with_flag(
786 &self,
787 key: &str,
788 new_topic: &str,
789 queue_num: i32,
790 topic_sys_flag: i32,
791 attributes: HashMap<String, String>,
792 ) -> ClientResult<()> {
793 let new_topic = self.with_namespace(new_topic);
794 self.try_impl_()?
795 .create_topic(key, new_topic.as_str(), queue_num, topic_sys_flag, attributes)
796 .await
797 }
798
799 pub async fn query_message(
801 &self,
802 topic: &str,
803 key: &str,
804 max_num: i32,
805 begin: u64,
806 end: u64,
807 ) -> ClientResult<QueryResult> {
808 let topic = self.with_namespace(topic);
809 self.try_impl_()?
810 .query_message(topic.as_str(), key, max_num, begin, end)
811 .await
812 }
813
814 pub async fn view_message(&self, topic: &str, msg_id: &str) -> ClientResult<MessageExt> {
816 let topic = self.with_namespace(topic);
817 let impl_ = self.try_impl_()?;
818 if MessageDecoder::decode_message_id(msg_id).is_ok() {
819 impl_.view_message(topic.as_str(), msg_id).await
820 } else {
821 impl_.query_message_by_uniq_key(topic.as_str(), msg_id).await
822 }
823 }
824
825 pub async fn pause(&self, message_queues: Vec<MessageQueue>) {
827 <Self as AssignmentControl>::pause(self, message_queues).await;
828 }
829
830 pub async fn resume(&self, message_queues: Vec<MessageQueue>) {
832 <Self as AssignmentControl>::resume(self, message_queues).await;
833 }
834
835 pub async fn is_paused(&self, message_queue: &MessageQueue) -> bool {
837 <Self as AssignmentControl>::is_paused(self, message_queue).await
838 }
839
840 pub async fn seek(&self, message_queue: &MessageQueue, offset: i64) -> ClientResult<()> {
842 <Self as AssignmentControl>::seek(self, message_queue, offset).await
843 }
844
845 pub async fn seek_to_begin(&self, message_queue: &MessageQueue) -> ClientResult<()> {
847 <Self as AssignmentControl>::seek_to_begin(self, message_queue).await
848 }
849
850 pub async fn seek_to_end(&self, message_queue: &MessageQueue) -> ClientResult<()> {
852 <Self as AssignmentControl>::seek_to_end(self, message_queue).await
853 }
854
855 pub async fn update_name_server_address(&self, name_server_address: &str) {
857 <Self as SubscriptionControl>::update_name_server_address(self, name_server_address).await;
858 }
859
860 pub async fn register_topic_message_queue_change_listener<TL>(&self, topic: &str, listener: TL) -> ClientResult<()>
862 where
863 TL: TopicMessageQueueChangeListener + 'static,
864 {
865 <Self as SubscriptionControl>::register_topic_message_queue_change_listener(self, topic, listener).await
866 }
867
868 pub fn consumer_group(&self) -> CheetahString {
870 self.consumer_config.load().consumer_group.clone()
871 }
872
873 pub fn get_consumer_group(&self) -> CheetahString {
875 self.consumer_group()
876 }
877
878 pub fn set_consumer_group(&self, consumer_group: impl Into<CheetahString>) -> ClientResult<()> {
885 let consumer_group = consumer_group.into();
886 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
887 impl_.set_consumer_group(consumer_group.clone())?;
888 }
889 self.update_consumer_config(|config| config.consumer_group = consumer_group.clone());
890 Ok(())
891 }
892
893 pub fn namespace(&self) -> Option<CheetahString> {
895 self.client_config.load().resolved_namespace()
896 }
897
898 pub fn customized_trace_topic(&self) -> Option<CheetahString> {
900 self.custom_trace_topic.clone()
901 }
902
903 pub fn get_customized_trace_topic(&self) -> Option<CheetahString> {
905 self.customized_trace_topic()
906 }
907
908 pub fn set_customized_trace_topic(&mut self, customized_trace_topic: impl Into<CheetahString>) {
910 self.custom_trace_topic = Some(customized_trace_topic.into());
911 }
912
913 pub fn clear_customized_trace_topic(&mut self) {
915 self.custom_trace_topic = None;
916 }
917
918 pub fn is_enable_msg_trace(&self) -> bool {
920 self.enable_msg_trace
921 }
922
923 pub fn set_enable_msg_trace(&mut self, enable_msg_trace: bool) {
925 self.enable_msg_trace = enable_msg_trace;
926 }
927
928 pub fn is_use_tls(&self) -> bool {
930 self.client_config.load().is_use_tls()
931 }
932
933 pub async fn set_use_tls(&self, use_tls: bool) {
935 self.update_client_config(|config| config.set_use_tls(use_tls));
936 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
937 impl_.set_use_tls(use_tls);
938 }
939 if let Some(dispatcher) = self.trace_dispatcher.read().await.as_ref().cloned() {
940 if let Some(async_dispatcher) = dispatcher.as_any().downcast_ref::<AsyncTraceDispatcher>() {
941 async_dispatcher.set_use_tls(use_tls);
942 }
943 }
944 }
945
946 pub async fn trace_dispatcher(&self) -> Option<Arc<dyn TraceDispatcher + Send + Sync>> {
948 self.trace_dispatcher.read().await.as_ref().cloned()
949 }
950
951 pub async fn get_trace_dispatcher(&self) -> Option<Arc<dyn TraceDispatcher + Send + Sync>> {
953 self.trace_dispatcher().await
954 }
955
956 pub fn client_config(&self) -> Arc<ClientConfig> {
958 self.client_config_snapshot()
959 }
960
961 pub fn consumer_config(&self) -> Arc<LitePullConsumerConfig> {
963 self.consumer_config_snapshot()
964 }
965
966 fn with_namespace(&self, resource: &str) -> CheetahString {
968 let resource = CheetahString::from(resource);
969 let namespace = self.client_config.load().resolved_namespace().unwrap_or_default();
970 if namespace.is_empty() || NamespaceUtil::is_already_with_namespace(resource.as_str(), namespace.as_str()) {
971 resource
972 } else {
973 NamespaceUtil::wrap_namespace(namespace, resource)
974 }
975 }
976
977 pub(crate) fn classic_topic_with_namespace(&self, topic: &str) -> CheetahString {
978 self.with_namespace(topic)
979 }
980
981 pub(crate) fn set_classic_pull_message_queue_listener(
982 &self,
983 listener: Option<ArcMessageQueueListener>,
984 ) -> ClientResult<()> {
985 self.set_message_queue_listener_local(listener.clone());
986 if let Some(implementation) = self.default_lite_pull_consumer_impl.get() {
987 implementation.set_message_queue_listener(listener);
988 }
989 Ok(())
990 }
991
992 fn without_namespace(&self, resource: &str) -> CheetahString {
994 match self.client_config.load().resolved_namespace() {
995 Some(namespace) if !namespace.is_empty() => {
996 NamespaceUtil::without_namespace_with_namespace(resource, namespace.as_str()).into()
997 }
998 _ => NamespaceUtil::without_namespace(resource).into(),
999 }
1000 }
1001
1002 fn consumer_group_with_namespace(&self) -> CheetahString {
1004 let consumer_group = self.consumer_config.load().consumer_group.clone();
1005 let namespace = self.client_config.load().resolved_namespace().unwrap_or_default();
1006 if namespace.is_empty() || NamespaceUtil::is_already_with_namespace(consumer_group.as_str(), namespace.as_str())
1007 {
1008 consumer_group
1009 } else {
1010 NamespaceUtil::wrap_namespace(namespace, consumer_group)
1011 }
1012 }
1013
1014 pub(crate) fn queue_with_namespace(&self, mq: &MessageQueue) -> MessageQueue {
1016 self.client_config.load().queue_with_resolved_namespace(mq.clone())
1017 }
1018
1019 fn queue_without_namespace(&self, mq: &MessageQueue) -> MessageQueue {
1021 match self.client_config.load().resolved_namespace() {
1022 Some(namespace) if !namespace.is_empty() => {
1023 let unwrapped_topic = NamespaceUtil::without_namespace_with_namespace(mq.topic(), namespace.as_str());
1024 MessageQueue::from_parts(unwrapped_topic, mq.broker_name().clone(), mq.queue_id())
1025 }
1026 Some(_) | None => mq.clone(),
1027 }
1028 }
1029
1030 async fn init_trace_dispatcher_internal(&self, impl_: &Arc<DefaultLitePullConsumerImpl>) -> ClientResult<()> {
1032 if !self.enable_msg_trace {
1033 return Ok(());
1034 }
1035
1036 let dispatcher_arc = {
1037 let mut dispatcher_guard = self.trace_dispatcher.write().await;
1038 if let Some(dispatcher) = dispatcher_guard.as_ref() {
1039 dispatcher.clone()
1040 } else {
1041 let client_config = self.client_config_snapshot();
1042 let consumer_config = self.consumer_config_snapshot();
1043 let trace_topic = self
1044 .custom_trace_topic
1045 .as_ref()
1046 .map(|t| t.as_str())
1047 .unwrap_or(TopicValidator::RMQ_SYS_TRACE_TOPIC);
1048
1049 let dispatcher = AsyncTraceDispatcher::new(
1050 self.session.runtime(),
1051 consumer_config.consumer_group.as_str(),
1052 Type::Consume,
1053 client_config.trace_msg_batch_num,
1054 trace_topic,
1055 self.rpc_hook.clone(),
1056 );
1057 dispatcher.set_namespace_v2(client_config.namespace_v2.clone());
1058 dispatcher.set_use_tls(client_config.use_tls);
1059
1060 let dispatcher_arc: Arc<dyn TraceDispatcher + Send + Sync> = Arc::new(dispatcher);
1061 *dispatcher_guard = Some(dispatcher_arc.clone());
1062 dispatcher_arc
1063 }
1064 };
1065
1066 let hook = Arc::new(ConsumeMessageTraceHookImpl::new(dispatcher_arc));
1067 impl_.register_consume_message_hook(hook);
1068
1069 Ok(())
1070 }
1071
1072 async fn start_trace_dispatcher(&self) {
1074 if !self.enable_msg_trace {
1075 return;
1076 }
1077
1078 let dispatcher = self.trace_dispatcher.read().await.as_ref().cloned();
1079 let Some(dispatcher) = dispatcher else {
1080 return;
1081 };
1082
1083 let client_config = self.client_config_snapshot();
1084 let name_server_addr = client_config
1085 .namesrv_addr
1086 .as_ref()
1087 .map(|addr| addr.as_str())
1088 .unwrap_or_default();
1089 if let Err(error) = dispatcher.start(name_server_addr, client_config.access_channel) {
1090 tracing::warn!("trace dispatcher start failed: {}", error);
1091 }
1092 }
1093
1094 pub(crate) fn try_impl_(&self) -> ClientResult<&Arc<DefaultLitePullConsumerImpl>> {
1096 self.default_lite_pull_consumer_impl
1097 .get()
1098 .ok_or_else(|| ClientError::not_initialized("DefaultLitePullConsumer not started. Call start() first."))
1099 }
1100
1101 async fn get_or_init_impl(&self) -> ClientResult<&Arc<DefaultLitePullConsumerImpl>> {
1108 self.default_lite_pull_consumer_impl
1109 .get_or_try_init(|| async {
1110 let impl_ = Arc::new(DefaultLitePullConsumerImpl::try_new_with_options(
1111 self.session.runtime(),
1112 ClientOptions::from_parts(
1113 self.client_config_snapshot().as_ref().clone(),
1114 self.nameserver_discovery.clone(),
1115 ),
1116 self.consumer_config_snapshot(),
1117 )?);
1118 impl_.bind_self();
1119 impl_.set_rpc_hook(self.rpc_hook.clone());
1120 impl_.set_message_queue_listener(self.current_message_queue_listener());
1121
1122 self.init_trace_dispatcher_internal(&impl_).await?;
1123
1124 let consumer_group = self.consumer_group_with_namespace();
1125 self.set_consumer_group(consumer_group.clone())?;
1126 impl_.set_consumer_group(consumer_group)?;
1127 if let Some(offset_store) = self.current_offset_store() {
1128 impl_.set_offset_store(Some(offset_store))?;
1129 }
1130
1131 Ok::<Arc<DefaultLitePullConsumerImpl>, crate::ClientError>(impl_)
1132 })
1133 .await
1134 }
1135
1136 fn current_message_queue_listener(&self) -> Option<ArcMessageQueueListener> {
1137 self.message_queue_listener
1138 .read()
1139 .ok()
1140 .and_then(|listener| listener.clone())
1141 }
1142
1143 fn set_message_queue_listener_local(&self, listener: Option<ArcMessageQueueListener>) {
1144 match self.message_queue_listener.write() {
1145 Ok(mut current) => *current = listener,
1146 Err(error) => tracing::warn!("LitePull message queue listener lock poisoned: {}", error),
1147 }
1148 }
1149
1150 fn current_offset_store(&self) -> Option<Arc<OffsetStore>> {
1151 self.offset_store.read().ok().and_then(|store| store.clone())
1152 }
1153
1154 fn set_offset_store_local(&self, offset_store: Option<Arc<OffsetStore>>) {
1155 match self.offset_store.write() {
1156 Ok(mut current) => *current = offset_store,
1157 Err(error) => tracing::warn!("LitePull offset store lock poisoned: {}", error),
1158 }
1159 }
1160
1161 pub(crate) async fn register_classic_pull_subscription(&self, topic: &CheetahString) -> ClientResult<()> {
1162 self.get_or_init_impl()
1163 .await?
1164 .register_classic_pull_subscription(topic)
1165 .await
1166 }
1167}
1168
1169#[allow(unused)]
1170impl ClientSessionProvider for DefaultLitePullConsumer {
1171 fn client_session(&self) -> Option<&ClientSession> {
1172 Some(&self.session)
1173 }
1174}
1175
1176impl SubscriptionControl for DefaultLitePullConsumer {
1177 async fn subscribe(&self, topic: &str) -> ClientResult<()> {
1178 self.subscribe_with_expression(topic, "*").await
1179 }
1180
1181 async fn subscribe_with_expression(&self, topic: &str, sub_expression: &str) -> ClientResult<()> {
1182 let wrapped_topic = self.with_namespace(topic);
1183 self.get_or_init_impl()
1184 .await?
1185 .subscribe(wrapped_topic, sub_expression)
1186 .await
1187 }
1188
1189 async fn subscribe_with_listener<MQL>(&self, topic: &str, sub_expression: &str, listener: MQL) -> ClientResult<()>
1190 where
1191 MQL: MessageQueueListener + 'static,
1192 {
1193 let wrapped_topic = self.with_namespace(topic);
1194 let listener: ArcMessageQueueListener = Arc::new(listener);
1195 self.get_or_init_impl()
1196 .await?
1197 .subscribe_with_listener_arc(wrapped_topic, sub_expression, listener.clone())
1198 .await?;
1199 self.set_message_queue_listener_local(Some(listener));
1200 Ok(())
1201 }
1202
1203 async fn subscribe_with_selector(&self, topic: &str, selector: Option<MessageSelector>) -> ClientResult<()> {
1204 let wrapped_topic = self.with_namespace(topic);
1205 self.get_or_init_impl()
1206 .await?
1207 .subscribe_with_selector(wrapped_topic, selector)
1208 .await
1209 }
1210
1211 async fn unsubscribe(&self, topic: &str) {
1212 let wrapped_topic = self.with_namespace(topic);
1213 match self.try_impl_() {
1214 Ok(impl_) => {
1215 if let Err(e) = impl_.unsubscribe(wrapped_topic).await {
1216 tracing::warn!(topic = %topic, error = %e, "unsubscribe failed");
1217 }
1218 }
1219 Err(e) => tracing::warn!(topic = %topic, error = %e, "unsubscribe failed"),
1220 }
1221 }
1222
1223 async fn build_subscriptions_for_heartbeat(
1224 &self,
1225 sub_expression_map: &mut HashMap<String, MessageSelector>,
1226 ) -> ClientResult<()> {
1227 self.try_impl_()?
1228 .build_subscriptions_for_heartbeat(sub_expression_map)
1229 .await
1230 }
1231
1232 async fn subscriptions_for_heartbeat(&self) -> HashSet<SubscriptionData> {
1233 self.default_lite_pull_consumer_impl
1234 .get()
1235 .map_or_else(HashSet::new, |impl_| impl_.subscriptions_for_heartbeat())
1236 }
1237
1238 async fn message_model(&self) -> MessageModel {
1239 self.consumer_config.load().message_model
1240 }
1241
1242 async fn set_message_model(&self, message_model: MessageModel) {
1243 self.update_consumer_config(|config| config.message_model = message_model);
1244 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1245 impl_.set_message_model(message_model);
1246 }
1247 }
1248
1249 async fn consume_from_where(&self) -> ConsumeFromWhere {
1250 self.consumer_config.load().consume_from_where
1251 }
1252
1253 async fn set_consume_from_where(&self, consume_from_where: ConsumeFromWhere) -> ClientResult<()> {
1254 validate_lite_pull_consume_from_where(consume_from_where)?;
1255 self.update_consumer_config(|config| config.consume_from_where = consume_from_where);
1256 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1257 impl_.set_consume_from_where(consume_from_where)?;
1258 }
1259 Ok(())
1260 }
1261
1262 async fn consume_timestamp(&self) -> Option<CheetahString> {
1263 self.consumer_config.load().consume_timestamp.clone()
1264 }
1265
1266 async fn set_consume_timestamp(&self, consume_timestamp: Option<CheetahString>) {
1267 self.update_consumer_config(|config| config.consume_timestamp = consume_timestamp.clone());
1268 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1269 impl_.set_consume_timestamp(consume_timestamp);
1270 }
1271 }
1272
1273 async fn allocate_message_queue_strategy(&self) -> Arc<dyn AllocateMessageQueueStrategy + Send + Sync> {
1274 let configured_strategy = self.consumer_config.load().allocate_message_queue_strategy.clone();
1275 self.default_lite_pull_consumer_impl
1276 .get()
1277 .map_or_else(|| configured_strategy, |impl_| impl_.allocate_message_queue_strategy())
1278 }
1279
1280 async fn set_allocate_message_queue_strategy(
1281 &self,
1282 allocate_message_queue_strategy: Arc<dyn AllocateMessageQueueStrategy + Send + Sync>,
1283 ) {
1284 self.update_consumer_config(|config| {
1285 config.allocate_message_queue_strategy = allocate_message_queue_strategy.clone();
1286 });
1287 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1288 impl_.set_allocate_message_queue_strategy(allocate_message_queue_strategy);
1289 }
1290 }
1291
1292 async fn message_queue_listener(&self) -> Option<ArcMessageQueueListener> {
1293 self.default_lite_pull_consumer_impl
1294 .get()
1295 .and_then(|impl_| impl_.message_queue_listener())
1296 .or_else(|| self.current_message_queue_listener())
1297 }
1298
1299 async fn set_message_queue_listener(&self, message_queue_listener: Option<ArcMessageQueueListener>) {
1300 self.set_message_queue_listener_local(message_queue_listener.clone());
1301 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1302 impl_.set_message_queue_listener(message_queue_listener);
1303 }
1304 }
1305
1306 async fn topic_metadata_check_interval_millis(&self) -> u64 {
1307 self.consumer_config.load().topic_metadata_check_interval_millis
1308 }
1309
1310 async fn set_topic_metadata_check_interval_millis(&self, interval_millis: u64) {
1311 self.update_consumer_config(|config| config.topic_metadata_check_interval_millis = interval_millis);
1312 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1313 impl_.set_topic_metadata_check_interval_millis(interval_millis);
1314 }
1315 }
1316
1317 async fn is_connect_broker_by_user(&self) -> bool {
1318 let configured = self.consumer_config.load().connect_broker_by_user;
1319 self.default_lite_pull_consumer_impl
1320 .get()
1321 .map_or(configured, |impl_| impl_.is_connect_broker_by_user())
1322 }
1323
1324 async fn set_connect_broker_by_user(&self, connect_broker_by_user: bool) {
1325 self.update_consumer_config(|config| config.connect_broker_by_user = connect_broker_by_user);
1326 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1327 impl_.set_connect_broker_by_user(connect_broker_by_user);
1328 }
1329 }
1330
1331 async fn default_broker_id(&self) -> u64 {
1332 let configured = self.consumer_config.load().default_broker_id;
1333 self.default_lite_pull_consumer_impl
1334 .get()
1335 .map_or(configured, |impl_| impl_.default_broker_id())
1336 }
1337
1338 async fn set_default_broker_id(&self, broker_id: u64) {
1339 self.update_consumer_config(|config| config.default_broker_id = broker_id);
1340 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1341 impl_.set_default_broker_id(broker_id);
1342 }
1343 }
1344
1345 async fn is_unit_mode(&self) -> bool {
1346 self.consumer_config.load().unit_mode
1347 }
1348
1349 async fn set_unit_mode(&self, unit_mode: bool) {
1350 self.update_consumer_config(|config| config.unit_mode = unit_mode);
1351 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1352 impl_.set_unit_mode(unit_mode);
1353 }
1354 }
1355
1356 async fn update_name_server_address(&self, name_server_address: &str) {
1357 self.update_client_config(|config| {
1358 config.set_namesrv_addr(CheetahString::from_slice(name_server_address));
1359 });
1360
1361 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1362 let addresses: Vec<String> = name_server_address
1363 .split(';')
1364 .map(|s| s.trim().to_string())
1365 .filter(|s| !s.is_empty())
1366 .collect();
1367 impl_.update_name_server_address(addresses).await;
1368 }
1369 }
1370
1371 async fn register_topic_message_queue_change_listener<TL>(&self, topic: &str, listener: TL) -> ClientResult<()>
1372 where
1373 TL: TopicMessageQueueChangeListener + 'static,
1374 {
1375 let wrapped_topic = self.with_namespace(topic);
1376 let listener_arc: Arc<dyn TopicMessageQueueChangeListener + Send + Sync> = Arc::new(listener);
1377 self.try_impl_()?
1378 .register_topic_message_queue_change_listener(wrapped_topic, listener_arc)
1379 .await
1380 }
1381}
1382
1383impl AssignmentControl for DefaultLitePullConsumer {
1384 async fn assignment(&self) -> ClientResult<HashSet<MessageQueue>> {
1385 let assignment = self.try_impl_()?.assignment().await;
1386
1387 let mut result = HashSet::with_capacity(assignment.len());
1389 for mq in assignment {
1390 result.insert(self.queue_without_namespace(&mq));
1391 }
1392
1393 Ok(result)
1394 }
1395
1396 async fn assign(&self, message_queues: Vec<MessageQueue>) -> ClientResult<()> {
1397 let wrapped_queues: Vec<_> = message_queues.iter().map(|mq| self.queue_with_namespace(mq)).collect();
1399
1400 self.get_or_init_impl().await?.assign(wrapped_queues).await
1401 }
1402
1403 async fn set_sub_expression_for_assign(&self, topic: &str, sub_expression: &str) -> ClientResult<()> {
1404 let wrapped_topic = self.with_namespace(topic);
1405 self.get_or_init_impl()
1406 .await?
1407 .set_sub_expression_for_assign(wrapped_topic, sub_expression)
1408 .await
1409 }
1410
1411 async fn pause(&self, message_queues: Vec<MessageQueue>) {
1412 let wrapped_queues: Vec<_> = message_queues.iter().map(|mq| self.queue_with_namespace(mq)).collect();
1413
1414 match self.try_impl_() {
1415 Ok(impl_) => impl_.pause(&wrapped_queues).await,
1416 Err(e) => tracing::warn!("pause failed: {}", e),
1417 }
1418 }
1419
1420 async fn resume(&self, message_queues: Vec<MessageQueue>) {
1421 let wrapped_queues: Vec<_> = message_queues.iter().map(|mq| self.queue_with_namespace(mq)).collect();
1422
1423 match self.try_impl_() {
1424 Ok(impl_) => impl_.resume(&wrapped_queues).await,
1425 Err(e) => tracing::warn!("resume failed: {}", e),
1426 }
1427 }
1428
1429 async fn is_paused(&self, message_queue: &MessageQueue) -> bool {
1430 let wrapped_mq = self.queue_with_namespace(message_queue);
1431 match self.try_impl_() {
1432 Ok(impl_) => impl_.is_paused(&wrapped_mq).await,
1433 Err(e) => {
1434 tracing::warn!("is_paused failed: {}", e);
1435 false
1436 }
1437 }
1438 }
1439
1440 async fn seek(&self, message_queue: &MessageQueue, offset: i64) -> ClientResult<()> {
1441 let wrapped_mq = self.queue_with_namespace(message_queue);
1442 self.try_impl_()?.seek(&wrapped_mq, offset).await
1443 }
1444
1445 async fn seek_to_begin(&self, message_queue: &MessageQueue) -> ClientResult<()> {
1446 let wrapped_mq = self.queue_with_namespace(message_queue);
1447 self.try_impl_()?.seek_to_begin(&wrapped_mq).await
1448 }
1449
1450 async fn seek_to_end(&self, message_queue: &MessageQueue) -> ClientResult<()> {
1451 let wrapped_mq = self.queue_with_namespace(message_queue);
1452 self.try_impl_()?.seek_to_end(&wrapped_mq).await
1453 }
1454}
1455
1456impl MessagePoll for DefaultLitePullConsumer {
1457 async fn poll_zero_copy(&self) -> Vec<Arc<MessageExt>> {
1459 let poll_timeout_millis = self.consumer_config.load().poll_timeout_millis;
1460 match self.try_impl_() {
1461 Ok(impl_) => match impl_.poll(poll_timeout_millis).await {
1462 Ok(messages) => messages,
1463 Err(e) => {
1464 tracing::error!(error = %e, "poll failed");
1465 Vec::new()
1466 }
1467 },
1468 Err(e) => {
1469 tracing::error!(error = %e, "poll failed");
1470 Vec::new()
1471 }
1472 }
1473 }
1474
1475 async fn poll_with_timeout_zero_copy(&self, timeout: u64) -> Vec<Arc<MessageExt>> {
1477 match self.try_impl_() {
1478 Ok(impl_) => match impl_.poll_with_timeout(timeout).await {
1479 Ok(messages) => messages,
1480 Err(e) => {
1481 tracing::error!(timeout_ms = timeout, error = %e, "poll failed");
1482 Vec::new()
1483 }
1484 },
1485 Err(e) => {
1486 tracing::error!(timeout_ms = timeout, error = %e, "poll failed");
1487 Vec::new()
1488 }
1489 }
1490 }
1491
1492 async fn poll(&self) -> Vec<MessageExt> {
1494 self.poll_zero_copy()
1495 .await
1496 .into_iter()
1497 .map(|arc_mut| (*arc_mut).clone())
1498 .collect()
1499 }
1500
1501 async fn poll_with_timeout(&self, timeout: u64) -> Vec<MessageExt> {
1503 self.poll_with_timeout_zero_copy(timeout)
1504 .await
1505 .into_iter()
1506 .map(|arc_mut| (*arc_mut).clone())
1507 .collect()
1508 }
1509
1510 async fn poll_timeout_millis(&self) -> u64 {
1511 self.consumer_config.load().poll_timeout_millis
1512 }
1513
1514 async fn set_poll_timeout_millis(&self, timeout_millis: u64) {
1515 self.update_consumer_config(|config| config.poll_timeout_millis = timeout_millis);
1516 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1517 impl_.set_poll_timeout_millis(timeout_millis);
1518 }
1519 }
1520
1521 async fn broker_suspend_max_time_millis(&self) -> u64 {
1522 self.consumer_config.load().broker_suspend_max_time_millis
1523 }
1524
1525 async fn set_broker_suspend_max_time_millis(&self, timeout_millis: u64) {
1526 self.update_consumer_config(|config| config.broker_suspend_max_time_millis = timeout_millis);
1527 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1528 impl_.set_broker_suspend_max_time_millis(timeout_millis);
1529 }
1530 }
1531
1532 async fn consumer_timeout_millis_when_suspend(&self) -> u64 {
1533 self.consumer_config.load().consumer_timeout_millis_when_suspend
1534 }
1535
1536 async fn set_consumer_timeout_millis_when_suspend(&self, timeout_millis: u64) {
1537 self.update_consumer_config(|config| config.consumer_timeout_millis_when_suspend = timeout_millis);
1538 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1539 impl_.set_consumer_timeout_millis_when_suspend(timeout_millis);
1540 }
1541 }
1542
1543 async fn consumer_pull_timeout_millis(&self) -> u64 {
1544 self.consumer_config.load().consumer_pull_timeout_millis
1545 }
1546
1547 async fn set_consumer_pull_timeout_millis(&self, timeout_millis: u64) {
1548 self.update_consumer_config(|config| config.consumer_pull_timeout_millis = timeout_millis);
1549 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1550 impl_.set_consumer_pull_timeout_millis(timeout_millis);
1551 }
1552 }
1553
1554 async fn pull_batch_size(&self) -> i32 {
1555 self.consumer_config.load().pull_batch_size
1556 }
1557
1558 async fn set_pull_batch_size(&self, pull_batch_size: i32) {
1559 self.update_consumer_config(|config| config.pull_batch_size = pull_batch_size);
1560 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1561 impl_.set_pull_batch_size(pull_batch_size);
1562 }
1563 }
1564
1565 async fn pull_thread_nums(&self) -> usize {
1566 self.consumer_config.load().pull_thread_nums
1567 }
1568
1569 async fn set_pull_thread_nums(&self, pull_thread_nums: usize) {
1570 if let Err(error) = self.try_set_pull_thread_nums(pull_thread_nums).await {
1571 tracing::warn!("Ignoring invalid pullThreadNums update: {error}");
1572 }
1573 }
1574
1575 async fn pull_threshold_for_all(&self) -> i64 {
1576 self.consumer_config.load().pull_threshold_for_all
1577 }
1578
1579 async fn set_pull_threshold_for_all(&self, pull_threshold_for_all: i64) {
1580 self.update_consumer_config(|config| config.pull_threshold_for_all = pull_threshold_for_all);
1581 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1582 impl_.set_pull_threshold_for_all(pull_threshold_for_all);
1583 }
1584 }
1585
1586 async fn pull_threshold_for_queue(&self) -> i64 {
1587 self.consumer_config.load().pull_threshold_for_queue
1588 }
1589
1590 async fn set_pull_threshold_for_queue(&self, pull_threshold_for_queue: i64) {
1591 self.update_consumer_config(|config| config.pull_threshold_for_queue = pull_threshold_for_queue);
1592 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1593 impl_.set_pull_threshold_for_queue(pull_threshold_for_queue);
1594 }
1595 }
1596
1597 async fn pull_threshold_size_for_queue(&self) -> i32 {
1598 self.consumer_config.load().pull_threshold_size_for_queue
1599 }
1600
1601 async fn set_pull_threshold_size_for_queue(&self, pull_threshold_size_for_queue: i32) {
1602 self.update_consumer_config(|config| config.pull_threshold_size_for_queue = pull_threshold_size_for_queue);
1603 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1604 impl_.set_pull_threshold_size_for_queue(pull_threshold_size_for_queue);
1605 }
1606 }
1607
1608 async fn consume_max_span(&self) -> i64 {
1609 self.consumer_config.load().consume_max_span
1610 }
1611
1612 async fn set_consume_max_span(&self, consume_max_span: i64) {
1613 self.update_consumer_config(|config| config.consume_max_span = consume_max_span);
1614 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1615 impl_.set_consume_max_span(consume_max_span);
1616 }
1617 }
1618}
1619
1620impl ConsumerOffsetControl for DefaultLitePullConsumer {
1621 async fn offset_store(&self) -> Option<Arc<OffsetStore>> {
1622 self.default_lite_pull_consumer_impl
1623 .get()
1624 .and_then(|impl_| impl_.offset_store())
1625 .or_else(|| self.current_offset_store())
1626 }
1627
1628 async fn set_offset_store(&self, offset_store: Option<Arc<OffsetStore>>) -> ClientResult<()> {
1629 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1630 impl_.set_offset_store(offset_store.clone())?;
1631 }
1632 self.set_offset_store_local(offset_store);
1633 Ok(())
1634 }
1635
1636 async fn fetch_message_queues(&self, topic: &str) -> ClientResult<Vec<MessageQueue>> {
1637 let wrapped_topic = self.with_namespace(topic);
1638 let queues = self.try_impl_()?.fetch_message_queues(wrapped_topic).await?;
1639
1640 let result: Vec<_> = queues.into_iter().map(|mq| self.queue_without_namespace(&mq)).collect();
1642
1643 Ok(result)
1644 }
1645
1646 async fn committed(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
1647 let wrapped_mq = self.queue_with_namespace(message_queue);
1648 self.try_impl_()?.committed(&wrapped_mq).await
1649 }
1650
1651 async fn commit_all(&self) -> ClientResult<()> {
1652 self.try_impl_()?.commit_all().await
1653 }
1654
1655 async fn commit_with_map(&self, offset_map: HashMap<MessageQueue, i64>, persist: bool) {
1656 let mut wrapped_offsets = HashMap::with_capacity(offset_map.len());
1658 for (mq, offset) in offset_map {
1659 wrapped_offsets.insert(self.queue_with_namespace(&mq), offset);
1660 }
1661
1662 match self.try_impl_() {
1663 Ok(impl_) => {
1664 if let Err(e) = impl_.commit(wrapped_offsets, persist).await {
1665 tracing::warn!("commit_with_map failed: {}", e);
1666 }
1667 }
1668 Err(e) => tracing::warn!("commit_with_map failed: {}", e),
1669 }
1670 }
1671
1672 async fn commit(&self) {
1673 if let Err(e) = self.commit_all().await {
1674 tracing::warn!("commit failed: {}", e);
1675 }
1676 }
1677
1678 async fn commit_with_set(&self, message_queues: HashSet<MessageQueue>, persist: bool) {
1679 let wrapped_queues: HashSet<_> = message_queues.iter().map(|mq| self.queue_with_namespace(mq)).collect();
1681 let impl_ = match self.try_impl_() {
1682 Ok(impl_) => impl_,
1683 Err(e) => {
1684 tracing::warn!("commit_with_set failed: {}", e);
1685 return;
1686 }
1687 };
1688
1689 if let Err(e) = impl_.commit_message_queues(&wrapped_queues, persist).await {
1690 tracing::warn!("commit_with_set failed: {}", e);
1691 }
1692 }
1693
1694 async fn commit_sync(&self) {
1695 if let Err(e) = self.commit_all().await {
1697 tracing::warn!("commit_sync failed: {}", e);
1698 }
1699 }
1700
1701 async fn commit_sync_with_map(&self, offset_map: HashMap<MessageQueue, i64>, persist: bool) {
1702 self.commit_with_map(offset_map, persist).await;
1704 }
1705
1706 async fn is_auto_commit(&self) -> bool {
1707 self.consumer_config.load().auto_commit
1708 }
1709
1710 async fn set_auto_commit(&self, auto_commit: bool) {
1711 self.update_consumer_config(|config| config.auto_commit = auto_commit);
1712 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1713 impl_.set_auto_commit(auto_commit);
1714 }
1715 }
1716
1717 async fn auto_commit_interval_millis(&self) -> u64 {
1718 self.consumer_config.load().auto_commit_interval_millis
1719 }
1720
1721 async fn set_auto_commit_interval_millis(&self, interval_millis: u64) {
1722 if interval_millis < MIN_AUTOCOMMIT_INTERVAL_MILLIS {
1723 return;
1724 }
1725 self.update_consumer_config(|config| config.auto_commit_interval_millis = interval_millis);
1726 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1727 impl_.set_auto_commit_interval_millis(interval_millis);
1728 }
1729 }
1730
1731 async fn offset_for_timestamp(&self, message_queue: &MessageQueue, timestamp: u64) -> ClientResult<i64> {
1732 let wrapped_mq = self.queue_with_namespace(message_queue);
1733 self.try_impl_()?.offset_for_timestamp(&wrapped_mq, timestamp).await
1734 }
1735
1736 async fn earliest_msg_store_time(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
1737 let wrapped_mq = self.queue_with_namespace(message_queue);
1738 self.try_impl_()?.earliest_msg_store_time(&wrapped_mq).await
1739 }
1740
1741 async fn max_offset(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
1742 let wrapped_mq = self.queue_with_namespace(message_queue);
1743 self.try_impl_()?.max_offset_public(&wrapped_mq).await
1744 }
1745
1746 async fn min_offset(&self, message_queue: &MessageQueue) -> ClientResult<i64> {
1747 let wrapped_mq = self.queue_with_namespace(message_queue);
1748 self.try_impl_()?.min_offset_public(&wrapped_mq).await
1749 }
1750}
1751
1752impl ConsumerLifecycle for DefaultLitePullConsumer {
1753 async fn start(&self) -> ClientResult<()> {
1754 let impl_ = self.get_or_init_impl().await?;
1755
1756 impl_.start().await?;
1757 self.set_offset_store_local(impl_.offset_store());
1758 self.start_trace_dispatcher().await;
1759 Ok(())
1760 }
1761
1762 async fn shutdown(&self) {
1763 if let Some(impl_) = self.default_lite_pull_consumer_impl.get() {
1764 let _ = impl_.shutdown().await;
1765 }
1766
1767 let dispatcher = { self.trace_dispatcher.write().await.take() };
1769 if let Some(dispatcher) = dispatcher {
1770 if let Some(async_dispatcher) = dispatcher.as_any().downcast_ref::<AsyncTraceDispatcher>() {
1771 async_dispatcher.shutdown_async().await;
1772 } else {
1773 dispatcher.shutdown();
1774 }
1775 }
1776 }
1777
1778 async fn is_running(&self) -> bool {
1779 match self.default_lite_pull_consumer_impl.get() {
1780 Some(impl_) => impl_.is_running().await,
1781 None => false,
1782 }
1783 }
1784}
1785
1786impl MQConsumer for DefaultLitePullConsumer {
1787 async fn create_topic(
1788 &mut self,
1789 key: &str,
1790 new_topic: &str,
1791 queue_num: i32,
1792 attributes: HashMap<String, String>,
1793 ) -> ClientResult<()> {
1794 DefaultLitePullConsumer::create_topic(self, key, new_topic, queue_num, attributes).await
1795 }
1796
1797 async fn create_topic_with_flag(
1798 &mut self,
1799 key: &str,
1800 new_topic: &str,
1801 queue_num: i32,
1802 topic_sys_flag: i32,
1803 attributes: HashMap<String, String>,
1804 ) -> ClientResult<()> {
1805 DefaultLitePullConsumer::create_topic_with_flag(self, key, new_topic, queue_num, topic_sys_flag, attributes)
1806 .await
1807 }
1808
1809 async fn query_message(
1810 &mut self,
1811 topic: &str,
1812 key: &str,
1813 max_num: i32,
1814 begin: u64,
1815 end: u64,
1816 ) -> ClientResult<QueryResult> {
1817 DefaultLitePullConsumer::query_message(self, topic, key, max_num, begin, end).await
1818 }
1819
1820 async fn view_message(&mut self, topic: &str, msg_id: &str) -> ClientResult<MessageExt> {
1821 DefaultLitePullConsumer::view_message(self, topic, msg_id).await
1822 }
1823
1824 async fn send_message_back(&mut self, _msg: MessageExt, _delay_level: i32, _broker_name: &str) -> ClientResult<()> {
1825 Err(crate::mq_client_err!(
1828 -1,
1829 "sendMessageBack is not supported in lite pull consumer"
1830 ))
1831 }
1832
1833 async fn fetch_subscribe_message_queues(&mut self, topic: &str) -> ClientResult<Vec<MessageQueue>> {
1834 let queues = self.fetch_message_queues(topic).await?;
1835 Ok(queues.into_iter().collect())
1836 }
1837
1838 async fn search_offset(&mut self, mq: &MessageQueue, timestamp: u64) -> ClientResult<i64> {
1839 <Self as ConsumerOffsetControl>::offset_for_timestamp(self, mq, timestamp).await
1840 }
1841
1842 async fn max_offset(&mut self, mq: &MessageQueue) -> ClientResult<i64> {
1843 <Self as ConsumerOffsetControl>::max_offset(self, mq).await
1844 }
1845
1846 async fn min_offset(&mut self, mq: &MessageQueue) -> ClientResult<i64> {
1847 <Self as ConsumerOffsetControl>::min_offset(self, mq).await
1848 }
1849
1850 async fn earliest_msg_store_time(&mut self, mq: &MessageQueue) -> ClientResult<i64> {
1851 <Self as ConsumerOffsetControl>::earliest_msg_store_time(self, mq).await
1852 }
1853}
1854
1855#[cfg(test)]
1856mod tests {
1857 use crate::test_support::error_assertions::assert_not_initialized;
1858 use crate::test_support::error_assertions::client_exception;
1859 use std::any::Any;
1860 use std::sync::atomic::AtomicUsize;
1861 use std::sync::atomic::Ordering;
1862 use std::sync::Mutex as StdMutex;
1863
1864 use super::*;
1865 use crate::base::access_channel::AccessChannel;
1866 use crate::common::acl_client_rpc_hook::AclClientRPCHook;
1867 use crate::common::session_credentials::SessionCredentials;
1868 use crate::consumer::mq_consumer_inner::MQConsumerInner;
1869 use crate::consumer::rebalance_strategy::allocate_message_queue_averagely_by_circle::AllocateMessageQueueAveragelyByCircle;
1870 use crate::consumer::store::read_offset_type::ReadOffsetType;
1871
1872 fn test_runtime() -> Arc<ClientRuntime> {
1873 crate::runtime::test_client_runtime("default-lite-pull-consumer-test")
1874 }
1875
1876 #[derive(Default)]
1877 struct CapturingTraceDispatcher {
1878 start_count: AtomicUsize,
1879 shutdown_count: AtomicUsize,
1880 append_count: AtomicUsize,
1881 last_name_srv_addr: StdMutex<Option<String>>,
1882 last_access_channel: StdMutex<Option<AccessChannel>>,
1883 }
1884
1885 impl TraceDispatcher for CapturingTraceDispatcher {
1886 fn start(&self, name_srv_addr: &str, access_channel: AccessChannel) -> ClientResult<()> {
1887 self.start_count.fetch_add(1, Ordering::SeqCst);
1888 *self.last_name_srv_addr.lock().expect("name server lock") = Some(name_srv_addr.to_string());
1889 *self.last_access_channel.lock().expect("access channel lock") = Some(access_channel);
1890 Ok(())
1891 }
1892
1893 fn append(&self, _ctx: &dyn Any) -> bool {
1894 self.append_count.fetch_add(1, Ordering::SeqCst);
1895 true
1896 }
1897
1898 fn flush(&self) -> ClientResult<()> {
1899 Ok(())
1900 }
1901
1902 fn shutdown(&self) {
1903 self.shutdown_count.fetch_add(1, Ordering::SeqCst);
1904 }
1905
1906 fn as_any(&self) -> &dyn Any {
1907 self
1908 }
1909
1910 fn as_mut_any(&mut self) -> &mut dyn Any {
1911 self
1912 }
1913 }
1914
1915 struct NoopMessageQueueListener;
1916
1917 impl MessageQueueListener for NoopMessageQueueListener {
1918 fn message_queue_changed(
1919 &self,
1920 _topic: &str,
1921 _mq_all: &HashSet<MessageQueue>,
1922 _mq_assigned: &HashSet<MessageQueue>,
1923 ) {
1924 }
1925 }
1926
1927 fn new_unstarted_consumer() -> DefaultLitePullConsumer {
1928 DefaultLitePullConsumer::builder(test_runtime())
1929 .consumer_group("lite_pull_group")
1930 .build()
1931 .expect("builder should create consumer")
1932 }
1933
1934 fn new_namespaced_consumer_with_impl() -> (DefaultLitePullConsumer, Arc<DefaultLitePullConsumerImpl>) {
1935 let client_runtime = test_runtime();
1936 let consumer = DefaultLitePullConsumer::builder(Arc::clone(&client_runtime))
1937 .consumer_group("lite_pull_namespace_group")
1938 .namespace("ns")
1939 .build()
1940 .expect("builder should create namespaced consumer");
1941 let impl_ = Arc::new(DefaultLitePullConsumerImpl::new(
1942 client_runtime,
1943 consumer.client_config_snapshot(),
1944 consumer.consumer_config_snapshot(),
1945 ));
1946 impl_.bind_self();
1947 if consumer.default_lite_pull_consumer_impl.set(impl_.clone()).is_err() {
1948 panic!("test consumer impl should be set once");
1949 }
1950
1951 (consumer, impl_)
1952 }
1953
1954 #[tokio::test]
1955 async fn assignment_before_start_returns_not_initialized_error() {
1956 let consumer = new_unstarted_consumer();
1957
1958 let error = consumer
1959 .assignment()
1960 .await
1961 .expect_err("assignment before start should fail");
1962
1963 assert_not_initialized(&error, "DefaultLitePullConsumer not started. Call start() first.");
1964 }
1965
1966 #[tokio::test]
1967 async fn consumer_running_info_before_start_returns_not_initialized_error() {
1968 let consumer = new_unstarted_consumer();
1969
1970 let error = consumer
1971 .consumer_running_info()
1972 .await
1973 .expect_err("running info before start should fail");
1974
1975 assert_not_initialized(&error, "DefaultLitePullConsumer not started. Call start() first.");
1976 }
1977
1978 #[tokio::test]
1979 async fn subscribe_before_start_initializes_impl_and_records_subscription_like_java() {
1980 let consumer = DefaultLitePullConsumer::builder(test_runtime())
1981 .consumer_group("lite_pull_pre_start_subscribe_group")
1982 .namespace("ns")
1983 .build()
1984 .expect("builder should create consumer");
1985
1986 consumer
1987 .subscribe_with_expression("TopicPreStart", "TagA")
1988 .await
1989 .expect("LitePull should accept subscribe before start like Java");
1990
1991 assert!(!consumer.is_running().await);
1992 let impl_ = consumer
1993 .try_impl_()
1994 .expect("pre-start subscribe should initialize the implementation");
1995 let subscriptions = impl_.subscriptions();
1996 let subscription = subscriptions
1997 .iter()
1998 .find(|subscription| subscription.topic.as_str() == "ns%TopicPreStart")
1999 .expect("pre-start subscribe should be stored in rebalance subscriptions");
2000
2001 assert_eq!(subscription.sub_string.as_str(), "TagA");
2002 }
2003
2004 #[tokio::test]
2005 async fn initialization_propagates_rpc_hook_to_impl() {
2006 let rpc_hook = Arc::new(AclClientRPCHook::new(SessionCredentials::with_keys(
2007 "access_key",
2008 "secret_key",
2009 )));
2010 let consumer = DefaultLitePullConsumer::builder(test_runtime())
2011 .consumer_group("lite_pull_rpc_hook_group")
2012 .rpc_hook(rpc_hook)
2013 .build()
2014 .expect("builder should create consumer with RPC hook");
2015
2016 let impl_ = consumer
2017 .get_or_init_impl()
2018 .await
2019 .expect("impl initialization should keep RPC hook");
2020
2021 assert!(impl_.has_rpc_hook(), "LitePull impl should retain builder RPC hook");
2022 }
2023
2024 #[tokio::test]
2025 async fn mq_consumer_offset_facade_delegates_to_lite_pull_impl_path() {
2026 let mut consumer = new_unstarted_consumer();
2027 let mq = MessageQueue::from_parts("TopicLite", "broker-a", 0);
2028
2029 let search_error = <DefaultLitePullConsumer as MQConsumer>::search_offset(&mut consumer, &mq, 1)
2030 .await
2031 .expect_err("searchOffset should enter LitePull path and fail because the consumer is not started");
2032 let max_error = <DefaultLitePullConsumer as MQConsumer>::max_offset(&mut consumer, &mq)
2033 .await
2034 .expect_err("maxOffset should enter LitePull path and fail because the consumer is not started");
2035 let min_error = <DefaultLitePullConsumer as MQConsumer>::min_offset(&mut consumer, &mq)
2036 .await
2037 .expect_err("minOffset should enter LitePull path and fail because the consumer is not started");
2038 let earliest_error = <DefaultLitePullConsumer as MQConsumer>::earliest_msg_store_time(&mut consumer, &mq)
2039 .await
2040 .expect_err("earliestMsgStoreTime should enter LitePull path and fail because the consumer is not started");
2041
2042 for error in [search_error, max_error, min_error, earliest_error] {
2043 assert_not_initialized(&error, "DefaultLitePullConsumer not started. Call start() first.");
2044 }
2045 }
2046
2047 #[tokio::test]
2048 async fn mq_consumer_admin_facade_delegates_to_lite_pull_impl_path() {
2049 let mut consumer = new_unstarted_consumer();
2050
2051 let create_error = <DefaultLitePullConsumer as MQConsumer>::create_topic(
2052 &mut consumer,
2053 TopicValidator::AUTO_CREATE_TOPIC_KEY_TOPIC,
2054 "TopicLiteAdmin",
2055 1,
2056 HashMap::new(),
2057 )
2058 .await
2059 .expect_err("createTopic should enter LitePull path and fail because the consumer is not started");
2060 let create_with_flag_error = <DefaultLitePullConsumer as MQConsumer>::create_topic_with_flag(
2061 &mut consumer,
2062 TopicValidator::AUTO_CREATE_TOPIC_KEY_TOPIC,
2063 "TopicLiteAdmin",
2064 1,
2065 0,
2066 HashMap::new(),
2067 )
2068 .await
2069 .expect_err("createTopicWithFlag should enter LitePull path and fail because the consumer is not started");
2070 let query_error =
2071 <DefaultLitePullConsumer as MQConsumer>::query_message(&mut consumer, "TopicLiteAdmin", "key", 32, 0, 1)
2072 .await
2073 .expect_err("queryMessage should enter LitePull path and fail because the consumer is not started");
2074 let view_error =
2075 <DefaultLitePullConsumer as MQConsumer>::view_message(&mut consumer, "TopicLiteAdmin", "not-a-msg-id")
2076 .await
2077 .expect_err("viewMessage should enter LitePull path and fail because the consumer is not started");
2078
2079 for error in [create_error, create_with_flag_error, query_error, view_error] {
2080 assert_not_initialized(&error, "DefaultLitePullConsumer not started. Call start() first.");
2081 }
2082 }
2083
2084 #[tokio::test]
2085 async fn consumer_running_info_facade_returns_lite_pull_snapshot() {
2086 let (consumer, _impl_) = new_namespaced_consumer_with_impl();
2087 consumer
2088 .subscribe_with_expression("TopicLiteRunningInfo", "TagA")
2089 .await
2090 .expect("subscribe should update running-info subscriptions");
2091 consumer.set_pull_batch_size(17).await;
2092 consumer.set_auto_commit(false).await;
2093 consumer.set_auto_commit_interval_millis(2_000).await;
2094
2095 let info = consumer
2096 .consumer_running_info()
2097 .await
2098 .expect("running info facade should delegate to impl");
2099
2100 assert_eq!(
2101 info.properties
2102 .get(ConsumerRunningInfo::PROP_CONSUME_TYPE)
2103 .map(String::as_str),
2104 Some("CONSUME_ACTIVELY")
2105 );
2106 assert_eq!(
2107 info.properties.get("consumerGroup").map(String::as_str),
2108 Some("lite_pull_namespace_group")
2109 );
2110 assert_eq!(info.properties.get("pullBatchSize").map(String::as_str), Some("17"));
2111 assert_eq!(info.properties.get("autoCommit").map(String::as_str), Some("false"));
2112 assert_eq!(
2113 info.properties.get("autoCommitIntervalMillis").map(String::as_str),
2114 Some("2000")
2115 );
2116 assert!(info
2117 .subscription_set
2118 .iter()
2119 .any(|subscription| subscription.topic.as_str() == "ns%TopicLiteRunningInfo"
2120 && subscription.sub_string.as_str() == "TagA"));
2121 }
2122
2123 #[tokio::test]
2124 async fn assign_surfaces_impl_errors_like_java() {
2125 let (consumer, _impl_) = new_namespaced_consumer_with_impl();
2126
2127 let error = consumer
2128 .assign(Vec::new())
2129 .await
2130 .expect_err("empty manual assignment should be rejected");
2131
2132 assert!(client_exception(&error)
2133 .to_string()
2134 .contains("Message queues can not be null or empty."));
2135 }
2136
2137 #[tokio::test]
2138 async fn offset_metadata_queries_before_start_return_not_initialized_error() {
2139 let consumer = new_unstarted_consumer();
2140 let queue = MessageQueue::from_parts("TopicA", "broker-a", 0);
2141
2142 let earliest_error = consumer
2143 .earliest_msg_store_time(&queue)
2144 .await
2145 .expect_err("earliest store time before start should fail");
2146 let max_error = consumer
2147 .max_offset(&queue)
2148 .await
2149 .expect_err("max offset before start should fail");
2150 let min_error = consumer
2151 .min_offset(&queue)
2152 .await
2153 .expect_err("min offset before start should fail");
2154
2155 assert_not_initialized(
2156 &earliest_error,
2157 "DefaultLitePullConsumer not started. Call start() first.",
2158 );
2159 assert_not_initialized(&max_error, "DefaultLitePullConsumer not started. Call start() first.");
2160 assert_not_initialized(&min_error, "DefaultLitePullConsumer not started. Call start() first.");
2161 }
2162
2163 #[tokio::test]
2164 async fn poll_before_start_returns_empty_vec_without_panic() {
2165 let consumer = new_unstarted_consumer();
2166
2167 assert!(consumer.poll_zero_copy().await.is_empty());
2168 assert!(consumer.poll_with_timeout_zero_copy(1).await.is_empty());
2169 }
2170
2171 #[tokio::test]
2172 async fn lite_pull_facade_namespace_subscribe_wraps_builder_namespace_like_java() {
2173 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2174
2175 assert_eq!(consumer.namespace().as_deref(), Some("ns"));
2176 consumer
2177 .subscribe_with_expression("TopicA", "TagA")
2178 .await
2179 .expect("subscribe should succeed with injected impl");
2180
2181 let subscriptions = impl_.subscriptions();
2182 let subscription = subscriptions
2183 .iter()
2184 .find(|subscription| subscription.topic.as_str() == "ns%TopicA")
2185 .expect("namespaced topic should be subscribed");
2186 assert_eq!(subscription.sub_string.as_str(), "TagA");
2187 assert!(!subscriptions
2188 .iter()
2189 .any(|subscription| subscription.topic.as_str() == "TopicA"));
2190 }
2191
2192 #[tokio::test]
2193 async fn subscriptions_for_heartbeat_returns_current_rebalance_subscriptions_like_java_getter() {
2194 let (consumer, _impl_) = new_namespaced_consumer_with_impl();
2195
2196 assert!(consumer.subscriptions_for_heartbeat().await.is_empty());
2197
2198 consumer
2199 .subscribe_with_expression("TopicA", "TagA")
2200 .await
2201 .expect("subscribe should succeed with injected impl");
2202
2203 let subscriptions = consumer.subscriptions_for_heartbeat().await;
2204 assert_eq!(subscriptions.len(), 1);
2205 let subscription = subscriptions.iter().next().expect("subscription should exist");
2206 assert_eq!(subscription.topic.as_str(), "ns%TopicA");
2207 assert_eq!(subscription.sub_string.as_str(), "TagA");
2208 }
2209
2210 #[tokio::test]
2211 async fn lite_pull_java_getter_aliases_delegate_to_config() {
2212 let consumer = new_unstarted_consumer();
2213
2214 assert_eq!(consumer.get_message_model().await, consumer.message_model().await);
2215 assert_eq!(
2216 consumer.get_consume_from_where().await,
2217 consumer.consume_from_where().await
2218 );
2219 assert_eq!(
2220 consumer.get_consume_timestamp().await,
2221 consumer.consume_timestamp().await
2222 );
2223 assert_eq!(
2224 consumer.get_allocate_message_queue_strategy().await.get_name(),
2225 consumer.allocate_message_queue_strategy().await.get_name()
2226 );
2227 assert_eq!(
2228 consumer.get_offset_store().await.is_some(),
2229 consumer.offset_store().await.is_some()
2230 );
2231 assert_eq!(
2232 consumer.get_topic_metadata_check_interval_millis().await,
2233 consumer.topic_metadata_check_interval_millis().await
2234 );
2235 assert_eq!(
2236 consumer.get_poll_timeout_millis().await,
2237 consumer.poll_timeout_millis().await
2238 );
2239 assert_eq!(
2240 consumer.get_consumer_timeout_millis_when_suspend().await,
2241 consumer.consumer_timeout_millis_when_suspend().await
2242 );
2243 assert_eq!(
2244 consumer.get_consumer_pull_timeout_millis().await,
2245 consumer.consumer_pull_timeout_millis().await
2246 );
2247 assert_eq!(consumer.get_pull_batch_size().await, consumer.pull_batch_size().await);
2248 assert_eq!(
2249 consumer.get_pull_threshold_for_all().await,
2250 consumer.pull_threshold_for_all().await
2251 );
2252 assert_eq!(
2253 consumer.get_pull_threshold_for_queue().await,
2254 consumer.pull_threshold_for_queue().await
2255 );
2256 assert_eq!(
2257 consumer.get_pull_threshold_size_for_queue().await,
2258 consumer.pull_threshold_size_for_queue().await
2259 );
2260 assert_eq!(
2261 consumer.get_auto_commit_interval_millis().await,
2262 consumer.auto_commit_interval_millis().await
2263 );
2264 }
2265
2266 #[tokio::test]
2267 async fn set_sub_expression_for_assign_surfaces_impl_errors_like_java() {
2268 let (consumer, _impl_) = new_namespaced_consumer_with_impl();
2269
2270 let error = consumer
2271 .set_sub_expression_for_assign("TopicA", " ")
2272 .await
2273 .expect_err("blank assign filter should be rejected");
2274 assert!(client_exception(&error)
2275 .to_string()
2276 .contains("subExpression can not be null or empty."));
2277
2278 consumer
2279 .set_sub_expression_for_assign("TopicA", "TagA")
2280 .await
2281 .expect("valid assign filter should be accepted before start");
2282 }
2283
2284 #[tokio::test]
2285 async fn set_auto_commit_updates_initialized_impl_like_java_facade_reference() {
2286 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2287
2288 assert!(consumer.is_auto_commit().await);
2289 assert!(impl_.is_auto_commit());
2290
2291 consumer.set_auto_commit(false).await;
2292
2293 assert!(!consumer.is_auto_commit().await);
2294 assert!(!impl_.is_auto_commit());
2295
2296 consumer.set_auto_commit(true).await;
2297
2298 assert!(consumer.is_auto_commit().await);
2299 assert!(impl_.is_auto_commit());
2300 }
2301
2302 #[tokio::test]
2303 async fn set_auto_commit_interval_updates_initialized_impl_and_ignores_invalid_like_java() {
2304 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2305
2306 assert_eq!(consumer.auto_commit_interval_millis().await, 5000);
2307 assert_eq!(impl_.auto_commit_interval_millis(), 5000);
2308
2309 consumer.set_auto_commit_interval_millis(2000).await;
2310
2311 assert_eq!(consumer.auto_commit_interval_millis().await, 2000);
2312 assert_eq!(impl_.auto_commit_interval_millis(), 2000);
2313
2314 consumer
2315 .set_auto_commit_interval_millis(MIN_AUTOCOMMIT_INTERVAL_MILLIS - 1)
2316 .await;
2317
2318 assert_eq!(consumer.auto_commit_interval_millis().await, 2000);
2319 assert_eq!(impl_.auto_commit_interval_millis(), 2000);
2320 }
2321
2322 #[tokio::test]
2323 async fn set_unit_mode_updates_initialized_impl_and_heartbeat_source_like_java() {
2324 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2325
2326 assert!(!consumer.is_unit_mode().await);
2327 assert!(!impl_.is_unit_mode());
2328 assert!(!MQConsumerInner::is_unit_mode(impl_.as_ref()));
2329
2330 consumer.set_unit_mode(true).await;
2331
2332 assert!(consumer.is_unit_mode().await);
2333 assert!(impl_.is_unit_mode());
2334 assert!(MQConsumerInner::is_unit_mode(impl_.as_ref()));
2335 }
2336
2337 #[test]
2338 fn set_consumer_group_updates_initialized_impl_and_rebalance_before_start_like_java() {
2339 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2340
2341 consumer
2342 .set_consumer_group("lite_pull_updated_group")
2343 .expect("consumer group should be mutable before start");
2344
2345 assert_eq!(consumer.consumer_group().as_str(), "lite_pull_updated_group");
2346 assert_eq!(impl_.consumer_group_config().as_str(), "lite_pull_updated_group");
2347 assert_eq!(
2348 MQConsumerInner::group_name(impl_.as_ref()).as_str(),
2349 "lite_pull_updated_group"
2350 );
2351 assert_eq!(
2352 impl_.rebalance_consumer_group_name().as_deref(),
2353 Some("lite_pull_updated_group")
2354 );
2355 }
2356
2357 #[test]
2358 fn start_namespace_wraps_consumer_group_like_java_lite_pull_start() {
2359 let (consumer, _impl_) = new_namespaced_consumer_with_impl();
2360
2361 assert_eq!(
2362 consumer.consumer_group_with_namespace().as_str(),
2363 "ns%lite_pull_namespace_group"
2364 );
2365
2366 consumer
2367 .set_consumer_group("ns%lite_pull_namespace_group")
2368 .expect("pre-wrapped group should be accepted before start");
2369
2370 assert_eq!(
2371 consumer.consumer_group_with_namespace().as_str(),
2372 "ns%lite_pull_namespace_group"
2373 );
2374 }
2375
2376 #[tokio::test]
2377 async fn set_message_queue_listener_updates_initialized_impl_like_java() {
2378 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2379
2380 assert!(consumer.message_queue_listener().await.is_none());
2381 assert!(impl_.message_queue_listener().is_none());
2382
2383 let listener: ArcMessageQueueListener = Arc::new(NoopMessageQueueListener);
2384 consumer.set_message_queue_listener(Some(listener.clone())).await;
2385
2386 let facade_listener = consumer
2387 .message_queue_listener()
2388 .await
2389 .expect("facade should return configured listener");
2390 let impl_listener = impl_
2391 .message_queue_listener()
2392 .expect("impl should receive configured listener");
2393 assert!(Arc::ptr_eq(&facade_listener, &listener));
2394 assert!(Arc::ptr_eq(&impl_listener, &listener));
2395
2396 consumer.set_message_queue_listener(None).await;
2397
2398 assert!(consumer.message_queue_listener().await.is_none());
2399 assert!(impl_.message_queue_listener().is_none());
2400 }
2401
2402 #[tokio::test]
2403 async fn set_offset_store_updates_initialized_impl_and_rebalance_like_java() {
2404 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2405 let queue = MessageQueue::from_parts("TopicA", "broker-a", 0);
2406 let offset_store = Arc::new(OffsetStore::new_test());
2407
2408 assert!(consumer.offset_store().await.is_none());
2409 assert!(impl_.offset_store().is_none());
2410 assert!(!impl_.rebalance_has_offset_store());
2411
2412 consumer
2413 .set_offset_store(Some(offset_store.clone()))
2414 .await
2415 .expect("offset store should be mutable before start");
2416 offset_store.update_offset(&queue, 42, false).await;
2417
2418 let facade_store = consumer
2419 .offset_store()
2420 .await
2421 .expect("facade should expose configured offset store");
2422 let impl_store = impl_
2423 .offset_store()
2424 .expect("impl should receive configured offset store");
2425 assert_eq!(
2426 facade_store.read_offset(&queue, ReadOffsetType::ReadFromMemory).await,
2427 42
2428 );
2429 assert_eq!(impl_store.read_offset(&queue, ReadOffsetType::ReadFromMemory).await, 42);
2430 assert!(impl_.rebalance_has_offset_store());
2431
2432 consumer
2433 .set_offset_store(None)
2434 .await
2435 .expect("offset store should be clearable before start");
2436
2437 assert!(consumer.offset_store().await.is_none());
2438 assert!(impl_.offset_store().is_none());
2439 assert!(!impl_.rebalance_has_offset_store());
2440 }
2441
2442 #[tokio::test]
2443 async fn set_allocate_message_queue_strategy_updates_initialized_impl_and_rebalance_like_java() {
2444 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2445
2446 assert_eq!(consumer.allocate_message_queue_strategy().await.get_name(), "AVG");
2447 assert_eq!(impl_.allocate_message_queue_strategy().get_name(), "AVG");
2448 assert_eq!(impl_.rebalance_allocate_message_queue_strategy_name(), None);
2449
2450 consumer
2451 .set_allocate_message_queue_strategy(Arc::new(AllocateMessageQueueAveragelyByCircle))
2452 .await;
2453
2454 assert_eq!(
2455 consumer.allocate_message_queue_strategy().await.get_name(),
2456 "AVG_BY_CIRCLE"
2457 );
2458 assert_eq!(impl_.allocate_message_queue_strategy().get_name(), "AVG_BY_CIRCLE");
2459 assert_eq!(
2460 impl_.rebalance_allocate_message_queue_strategy_name(),
2461 Some("AVG_BY_CIRCLE")
2462 );
2463 }
2464
2465 #[tokio::test]
2466 #[allow(deprecated)]
2467 async fn core_runtime_config_setters_update_initialized_impl_like_java_facade_reference() {
2468 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2469
2470 assert_eq!(consumer.message_model().await, MessageModel::Clustering);
2471 assert_eq!(impl_.message_model_config(), MessageModel::Clustering);
2472 assert_eq!(MQConsumerInner::message_model(impl_.as_ref()), MessageModel::Clustering);
2473
2474 consumer.set_message_model(MessageModel::Broadcasting).await;
2475
2476 assert_eq!(consumer.message_model().await, MessageModel::Broadcasting);
2477 assert_eq!(impl_.message_model_config(), MessageModel::Broadcasting);
2478 assert_eq!(
2479 MQConsumerInner::message_model(impl_.as_ref()),
2480 MessageModel::Broadcasting
2481 );
2482
2483 assert_eq!(
2484 consumer.consume_from_where().await,
2485 ConsumeFromWhere::ConsumeFromLastOffset
2486 );
2487 consumer
2488 .set_consume_from_where(ConsumeFromWhere::ConsumeFromFirstOffset)
2489 .await
2490 .expect("valid Java LitePull consumeFromWhere should be accepted");
2491
2492 assert_eq!(
2493 consumer.consume_from_where().await,
2494 ConsumeFromWhere::ConsumeFromFirstOffset
2495 );
2496 assert_eq!(
2497 impl_.consume_from_where_config(),
2498 ConsumeFromWhere::ConsumeFromFirstOffset
2499 );
2500 assert_eq!(
2501 MQConsumerInner::consume_from_where(impl_.as_ref()),
2502 ConsumeFromWhere::ConsumeFromFirstOffset
2503 );
2504
2505 let error = consumer
2506 .set_consume_from_where(ConsumeFromWhere::ConsumeFromMaxOffset)
2507 .await
2508 .expect_err("Java LitePull rejects legacy consumeFromWhere values");
2509 assert!(client_exception(&error)
2510 .to_string()
2511 .contains("Invalid ConsumeFromWhere Value"));
2512 assert_eq!(
2513 consumer.consume_from_where().await,
2514 ConsumeFromWhere::ConsumeFromFirstOffset
2515 );
2516
2517 let timestamp = CheetahString::from_static_str("20250102030405");
2518 consumer.set_consume_timestamp(Some(timestamp.clone())).await;
2519
2520 assert_eq!(consumer.consume_timestamp().await, Some(timestamp.clone()));
2521 assert_eq!(impl_.consume_timestamp(), Some(timestamp));
2522
2523 assert_eq!(consumer.topic_metadata_check_interval_millis().await, 30_000);
2524 assert_eq!(impl_.topic_metadata_check_interval_millis(), 30_000);
2525
2526 consumer.set_topic_metadata_check_interval_millis(12_345).await;
2527
2528 assert_eq!(consumer.topic_metadata_check_interval_millis().await, 12_345);
2529 assert_eq!(impl_.topic_metadata_check_interval_millis(), 12_345);
2530 }
2531
2532 #[tokio::test]
2533 async fn set_poll_timeout_updates_initialized_impl_like_java_facade_reference() {
2534 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2535
2536 assert_eq!(consumer.poll_timeout_millis().await, 5000);
2537 assert_eq!(impl_.poll_timeout_millis(), 5000);
2538
2539 consumer.set_poll_timeout_millis(1234).await;
2540
2541 assert_eq!(consumer.poll_timeout_millis().await, 1234);
2542 assert_eq!(impl_.poll_timeout_millis(), 1234);
2543 }
2544
2545 #[tokio::test]
2546 async fn long_polling_timeout_setters_update_initialized_impl_like_java_facade_reference() {
2547 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2548
2549 assert_eq!(consumer.broker_suspend_max_time_millis().await, 20_000);
2550 assert_eq!(impl_.broker_suspend_max_time_millis(), 20_000);
2551 assert_eq!(consumer.consumer_timeout_millis_when_suspend().await, 30_000);
2552 assert_eq!(impl_.consumer_timeout_millis_when_suspend(), 30_000);
2553 assert_eq!(consumer.consumer_pull_timeout_millis().await, 10_000);
2554 assert_eq!(impl_.consumer_pull_timeout_millis(), 10_000);
2555
2556 consumer.set_broker_suspend_max_time_millis(11_111).await;
2557 consumer.set_consumer_timeout_millis_when_suspend(22_222).await;
2558 consumer.set_consumer_pull_timeout_millis(12_345).await;
2559
2560 assert_eq!(consumer.broker_suspend_max_time_millis().await, 11_111);
2561 assert_eq!(impl_.broker_suspend_max_time_millis(), 11_111);
2562 assert_eq!(consumer.consumer_timeout_millis_when_suspend().await, 22_222);
2563 assert_eq!(impl_.consumer_timeout_millis_when_suspend(), 22_222);
2564 assert_eq!(consumer.consumer_pull_timeout_millis().await, 12_345);
2565 assert_eq!(impl_.consumer_pull_timeout_millis(), 12_345);
2566 }
2567
2568 #[tokio::test]
2569 async fn pull_flow_control_setters_update_initialized_impl_like_java_facade_reference() {
2570 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2571
2572 consumer.set_pull_batch_size(64).await;
2573 consumer.set_pull_thread_nums(12).await;
2574 consumer.set_pull_threshold_for_all(20_000).await;
2575 consumer.set_pull_threshold_for_queue(2_000).await;
2576 consumer.set_pull_threshold_size_for_queue(256).await;
2577 consumer.set_consume_max_span(4_000).await;
2578
2579 assert_eq!(consumer.pull_batch_size().await, 64);
2580 assert_eq!(impl_.pull_batch_size(), 64);
2581 assert_eq!(consumer.pull_thread_nums().await, 12);
2582 assert_eq!(impl_.pull_thread_nums(), 12);
2583 assert_eq!(consumer.pull_threshold_for_all().await, 20_000);
2584 assert_eq!(impl_.pull_threshold_for_all(), 20_000);
2585 assert_eq!(consumer.pull_threshold_for_queue().await, 2_000);
2586 assert_eq!(impl_.pull_threshold_for_queue(), 2_000);
2587 assert_eq!(consumer.pull_threshold_size_for_queue().await, 256);
2588 assert_eq!(impl_.pull_threshold_size_for_queue(), 256);
2589 assert_eq!(consumer.consume_max_span().await, 4_000);
2590 assert_eq!(impl_.consume_max_span(), 4_000);
2591 }
2592
2593 #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
2594 async fn concurrent_facade_updates_publish_complete_immutable_snapshots() {
2595 let consumer = Arc::new(new_unstarted_consumer());
2596 let original = consumer.consumer_config();
2597 let barrier = Arc::new(tokio::sync::Barrier::new(4));
2598
2599 let batch_consumer = consumer.clone();
2600 let batch_barrier = barrier.clone();
2601 let batch = tokio::spawn(async move {
2602 batch_barrier.wait().await;
2603 batch_consumer.set_pull_batch_size(64).await;
2604 });
2605
2606 let threads_consumer = consumer.clone();
2607 let threads_barrier = barrier.clone();
2608 let threads = tokio::spawn(async move {
2609 threads_barrier.wait().await;
2610 threads_consumer.set_pull_thread_nums(12).await;
2611 });
2612
2613 let threshold_consumer = consumer.clone();
2614 let threshold_barrier = barrier.clone();
2615 let threshold = tokio::spawn(async move {
2616 threshold_barrier.wait().await;
2617 threshold_consumer.set_pull_threshold_for_all(20_000).await;
2618 });
2619
2620 let span_consumer = consumer.clone();
2621 let span = tokio::spawn(async move {
2622 barrier.wait().await;
2623 span_consumer.set_consume_max_span(4_000).await;
2624 });
2625
2626 for update in [batch, threads, threshold, span] {
2627 update.await.expect("facade config update should complete");
2628 }
2629
2630 let current = consumer.consumer_config();
2631 assert_eq!(current.pull_batch_size, 64);
2632 assert_eq!(current.pull_thread_nums, 12);
2633 assert_eq!(current.pull_threshold_for_all, 20_000);
2634 assert_eq!(current.consume_max_span, 4_000);
2635 assert_ne!(original.pull_batch_size, current.pull_batch_size);
2636 assert_ne!(original.pull_thread_nums, current.pull_thread_nums);
2637 assert_ne!(original.pull_threshold_for_all, current.pull_threshold_for_all);
2638 assert_ne!(original.consume_max_span, current.consume_max_span);
2639 }
2640
2641 #[tokio::test]
2642 async fn broker_selection_setters_update_facade_config_like_java() {
2643 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2644
2645 assert!(!consumer.is_connect_broker_by_user().await);
2646 assert_eq!(
2647 consumer.default_broker_id().await,
2648 rocketmq_model::common::mix_all::MASTER_ID
2649 );
2650 assert!(!impl_.is_connect_broker_by_user());
2651 assert_eq!(impl_.default_broker_id(), rocketmq_model::common::mix_all::MASTER_ID);
2652
2653 consumer.set_connect_broker_by_user(true).await;
2654 consumer.set_default_broker_id(3).await;
2655
2656 assert!(consumer.is_connect_broker_by_user().await);
2657 assert_eq!(consumer.default_broker_id().await, 3);
2658 assert!(impl_.is_connect_broker_by_user());
2659 assert_eq!(impl_.default_broker_id(), 3);
2660 }
2661
2662 #[test]
2663 fn lite_pull_facade_namespace_helpers_use_primary_namespace_like_java() {
2664 let (consumer, _) = new_namespaced_consumer_with_impl();
2665 let queue = MessageQueue::from_parts("TopicB", "broker-a", 3);
2666
2667 assert_eq!(consumer.with_namespace("TopicB").as_str(), "ns%TopicB");
2668 assert_eq!(consumer.with_namespace("ns%TopicB").as_str(), "ns%TopicB");
2669 assert_eq!(consumer.without_namespace("ns%TopicB").as_str(), "TopicB");
2670 assert_eq!(consumer.queue_with_namespace(&queue).topic_str(), "ns%TopicB");
2671 assert_eq!(
2672 consumer
2673 .queue_without_namespace(&MessageQueue::from_parts("ns%TopicB", "broker-a", 3))
2674 .topic_str(),
2675 "TopicB"
2676 );
2677 }
2678
2679 #[tokio::test]
2680 async fn trace_config_accessors_match_java_facade_fields() {
2681 let mut consumer = new_unstarted_consumer();
2682
2683 assert!(!consumer.is_enable_msg_trace());
2684 assert!(consumer.customized_trace_topic().is_none());
2685 assert!(consumer.trace_dispatcher().await.is_none());
2686
2687 consumer.set_enable_msg_trace(true);
2688 consumer.set_customized_trace_topic("TraceTopic");
2689
2690 assert!(consumer.is_enable_msg_trace());
2691 assert_eq!(consumer.customized_trace_topic().as_deref(), Some("TraceTopic"));
2692
2693 consumer.clear_customized_trace_topic();
2694
2695 assert!(consumer.customized_trace_topic().is_none());
2696 }
2697
2698 #[tokio::test]
2699 async fn lite_pull_use_tls_facade_updates_shared_impl_config_like_java_client_config() {
2700 let (consumer, impl_) = new_namespaced_consumer_with_impl();
2701
2702 assert!(!consumer.is_use_tls());
2703 assert!(!impl_.client_config.load().is_use_tls());
2704
2705 consumer.set_use_tls(true).await;
2706
2707 assert!(consumer.is_use_tls());
2708 assert!(consumer.client_config().is_use_tls());
2709 assert!(impl_.client_config.load().is_use_tls());
2710 }
2711
2712 #[tokio::test]
2713 async fn lite_pull_use_tls_facade_updates_async_trace_dispatcher() {
2714 let dispatcher = Arc::new(AsyncTraceDispatcher::new(
2715 test_runtime(),
2716 "lite_pull_tls_trace_group",
2717 Type::Consume,
2718 1,
2719 "",
2720 None,
2721 ));
2722 let consumer = DefaultLitePullConsumer::new(
2723 test_runtime(),
2724 ClientConfig::default(),
2725 LitePullConsumerConfig {
2726 consumer_group: CheetahString::from_static_str("lite_pull_tls_trace_group"),
2727 ..Default::default()
2728 },
2729 None,
2730 Some(dispatcher.clone()),
2731 true,
2732 None,
2733 );
2734
2735 assert!(!consumer.is_use_tls());
2736 assert!(!dispatcher.is_use_tls());
2737
2738 consumer.set_use_tls(true).await;
2739
2740 assert!(consumer.is_use_tls());
2741 assert!(dispatcher.is_use_tls());
2742 }
2743
2744 #[tokio::test]
2745 async fn trace_init_uses_configured_batch_num_like_java() {
2746 let client_runtime = test_runtime();
2747 let mut client_config = ClientConfig::default();
2748 client_config.set_trace_msg_batch_num(6);
2749 let consumer = DefaultLitePullConsumer::new(
2750 Arc::clone(&client_runtime),
2751 client_config,
2752 LitePullConsumerConfig {
2753 consumer_group: CheetahString::from_static_str("lite_pull_trace_batch_group"),
2754 ..Default::default()
2755 },
2756 None,
2757 None,
2758 true,
2759 None,
2760 );
2761 let impl_ = Arc::new(DefaultLitePullConsumerImpl::new(
2762 client_runtime,
2763 consumer.client_config_snapshot(),
2764 consumer.consumer_config_snapshot(),
2765 ));
2766 impl_.bind_self();
2767
2768 consumer
2769 .init_trace_dispatcher_internal(&impl_)
2770 .await
2771 .expect("trace init should create dispatcher");
2772 let dispatcher = consumer
2773 .trace_dispatcher
2774 .read()
2775 .await
2776 .as_ref()
2777 .expect("trace dispatcher should be initialized")
2778 .clone();
2779 let async_dispatcher = dispatcher
2780 .as_any()
2781 .downcast_ref::<AsyncTraceDispatcher>()
2782 .expect("default trace dispatcher should be AsyncTraceDispatcher");
2783 assert_eq!(async_dispatcher.batch_num(), 6);
2784 }
2785
2786 #[tokio::test]
2787 async fn trace_init_registers_custom_dispatcher_and_starts_with_client_config() {
2788 let client_runtime = test_runtime();
2789 let dispatcher = Arc::new(CapturingTraceDispatcher::default());
2790 let mut client_config = ClientConfig::default();
2791 client_config.set_namesrv_addr(CheetahString::from_static_str("127.0.0.1:9876"));
2792 client_config.set_access_channel(AccessChannel::Cloud);
2793
2794 let consumer = DefaultLitePullConsumer::new(
2795 Arc::clone(&client_runtime),
2796 client_config,
2797 LitePullConsumerConfig {
2798 consumer_group: CheetahString::from_static_str("lite_pull_trace_group"),
2799 ..Default::default()
2800 },
2801 None,
2802 Some(dispatcher.clone()),
2803 true,
2804 None,
2805 );
2806 let impl_ = Arc::new(DefaultLitePullConsumerImpl::new(
2807 client_runtime,
2808 consumer.client_config_snapshot(),
2809 consumer.consumer_config_snapshot(),
2810 ));
2811 impl_.bind_self();
2812
2813 consumer
2814 .init_trace_dispatcher_internal(&impl_)
2815 .await
2816 .expect("trace init should register hook");
2817 assert_eq!(impl_.consume_message_hook_count(), 1);
2818
2819 consumer.start_trace_dispatcher().await;
2820 assert_eq!(dispatcher.start_count.load(Ordering::SeqCst), 1);
2821 assert_eq!(
2822 dispatcher
2823 .last_name_srv_addr
2824 .lock()
2825 .expect("name server lock")
2826 .as_deref(),
2827 Some("127.0.0.1:9876")
2828 );
2829 assert_eq!(
2830 *dispatcher.last_access_channel.lock().expect("access channel lock"),
2831 Some(AccessChannel::Cloud)
2832 );
2833 }
2834}