rocketmq_client_rust/consumer/
mq_consumer_inner.rs1use std::collections::HashMap;
16use std::collections::HashSet;
17use std::sync::Arc;
18
19use cheetah_string::CheetahString;
20use rocketmq_model::common::consumer::consume_from_where::ConsumeFromWhere;
21use rocketmq_model::common::message::message_ext::MessageExt;
22use rocketmq_model::common::message::message_queue::MessageQueue;
23use rocketmq_protocol::protocol::body::consume_message_directly_result::ConsumeMessageDirectlyResult;
24use rocketmq_protocol::protocol::body::consumer_running_info::ConsumerRunningInfo;
25use rocketmq_protocol::protocol::heartbeat::consume_type::ConsumeType;
26use rocketmq_protocol::protocol::heartbeat::message_model::MessageModel;
27use rocketmq_protocol::protocol::heartbeat::subscription_data::SubscriptionData;
28
29use crate::consumer::consumer_impl::default_lite_pull_consumer_impl::DefaultLitePullConsumerImpl;
30use crate::consumer::consumer_impl::default_mq_push_consumer_impl::DefaultMQPushConsumerImpl;
31use crate::consumer::consumer_impl::pop_request::PopRequest;
32use crate::consumer::consumer_impl::pull_request::PullRequest;
33
34#[trait_variant::make(MQConsumerInner: Send)]
39pub trait MQConsumerInnerLocal: MQConsumerInnerAny + Sync + 'static {
40 fn group_name(&self) -> CheetahString;
42
43 fn message_model(&self) -> MessageModel;
45
46 fn consume_type(&self) -> ConsumeType;
48
49 fn consume_from_where(&self) -> ConsumeFromWhere;
51
52 fn subscriptions(&self) -> HashSet<SubscriptionData>;
54
55 async fn do_rebalance(&self);
57
58 async fn try_rebalance(&self) -> crate::ClientResult<bool>;
61
62 async fn persist_consumer_offset(&self);
64
65 async fn update_topic_subscribe_info(&self, topic: CheetahString, info: &HashSet<MessageQueue>);
72
73 async fn is_subscribe_topic_need_update(&self, topic: &str) -> bool;
83
84 fn is_unit_mode(&self) -> bool;
86
87 async fn reset_offsets(&self, topic: &CheetahString, offsets: HashMap<MessageQueue, i64>);
89
90 async fn consumer_status(&self, topic: &CheetahString) -> HashMap<MessageQueue, i64>;
92
93 async fn consumer_running_info(&self) -> ConsumerRunningInfo;
95}
96
97pub trait MQConsumerInnerAny: std::any::Any {
98 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
99
100 fn as_any(&self) -> &dyn std::any::Any;
101}
102
103impl<T: MQConsumerInner> MQConsumerInnerAny for T {
104 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
105 self
106 }
107
108 fn as_any(&self) -> &dyn std::any::Any {
109 self
110 }
111}
112
113#[derive(Clone)]
114pub struct MQConsumerInnerImpl {
115 inner: MQConsumerInnerImplKind,
116}
117
118#[derive(Clone)]
119enum MQConsumerInnerImplKind {
120 Push(Arc<DefaultMQPushConsumerImpl>),
121 LitePull(Arc<DefaultLitePullConsumerImpl>),
122}
123
124impl MQConsumerInnerImpl {
125 pub(crate) fn from_push(default_mqpush_consumer_impl: Arc<DefaultMQPushConsumerImpl>) -> Self {
126 Self {
127 inner: MQConsumerInnerImplKind::Push(default_mqpush_consumer_impl),
128 }
129 }
130
131 pub(crate) fn from_lite_pull(default_lite_pull_consumer_impl: Arc<DefaultLitePullConsumerImpl>) -> Self {
132 Self {
133 inner: MQConsumerInnerImplKind::LitePull(default_lite_pull_consumer_impl),
134 }
135 }
136
137 pub(crate) fn is_push_consumer(&self) -> bool {
138 matches!(self.inner, MQConsumerInnerImplKind::Push(_))
139 }
140
141 pub(crate) async fn pop_message(&mut self, pop_request: PopRequest) {
142 match &mut self.inner {
143 MQConsumerInnerImplKind::Push(consumer) => consumer.pop_message(pop_request).await,
144 MQConsumerInnerImplKind::LitePull(consumer) => {
145 tracing::warn!(
146 "Ignoring broker pop request for lite pull consumer group={}",
147 MQConsumerInner::group_name(consumer.as_ref())
148 );
149 }
150 }
151 }
152
153 pub(crate) async fn pull_message(&mut self, pull_request: PullRequest) {
154 match &mut self.inner {
155 MQConsumerInnerImplKind::Push(consumer) => consumer.pull_message(pull_request).await,
156 MQConsumerInnerImplKind::LitePull(consumer) => {
157 tracing::warn!(
158 "Ignoring broker pull request for lite pull consumer group={}",
159 MQConsumerInner::group_name(consumer.as_ref())
160 );
161 }
162 }
163 }
164
165 pub(crate) async fn consume_message_directly(
166 &self,
167 msg: MessageExt,
168 broker_name: Option<CheetahString>,
169 ) -> Option<ConsumeMessageDirectlyResult> {
170 match &self.inner {
171 MQConsumerInnerImplKind::Push(consumer) => consumer.consume_message_directly(msg, broker_name).await,
172 MQConsumerInnerImplKind::LitePull(consumer) => {
173 tracing::warn!(
174 "consumeMessageDirectly is not supported for lite pull consumer group={}",
175 MQConsumerInner::group_name(consumer.as_ref())
176 );
177 None
178 }
179 }
180 }
181}
182
183impl MQConsumerInner for MQConsumerInnerImpl {
184 #[inline]
185 fn group_name(&self) -> CheetahString {
186 match &self.inner {
187 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::group_name(consumer.as_ref()),
188 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::group_name(consumer.as_ref()),
189 }
190 }
191
192 #[inline]
193 fn message_model(&self) -> MessageModel {
194 match &self.inner {
195 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::message_model(consumer.as_ref()),
196 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::message_model(consumer.as_ref()),
197 }
198 }
199
200 #[inline]
201 fn consume_type(&self) -> ConsumeType {
202 match &self.inner {
203 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::consume_type(consumer.as_ref()),
204 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::consume_type(consumer.as_ref()),
205 }
206 }
207
208 #[inline]
209 fn consume_from_where(&self) -> ConsumeFromWhere {
210 match &self.inner {
211 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::consume_from_where(consumer.as_ref()),
212 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::consume_from_where(consumer.as_ref()),
213 }
214 }
215
216 #[inline]
217 fn subscriptions(&self) -> HashSet<SubscriptionData> {
218 match &self.inner {
219 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::subscriptions(consumer.as_ref()),
220 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::subscriptions(consumer.as_ref()),
221 }
222 }
223
224 #[inline]
225 async fn do_rebalance(&self) {
226 match &self.inner {
227 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::do_rebalance(consumer.as_ref()).await,
228 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::do_rebalance(consumer.as_ref()).await,
229 }
230 }
231
232 #[inline]
233 async fn try_rebalance(&self) -> crate::ClientResult<bool> {
234 match &self.inner {
235 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::try_rebalance(consumer.as_ref()).await,
236 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::try_rebalance(consumer.as_ref()).await,
237 }
238 }
239
240 #[inline]
241 async fn persist_consumer_offset(&self) {
242 match &self.inner {
243 MQConsumerInnerImplKind::Push(consumer) => {
244 MQConsumerInner::persist_consumer_offset(consumer.as_ref()).await
245 }
246 MQConsumerInnerImplKind::LitePull(consumer) => {
247 MQConsumerInner::persist_consumer_offset(consumer.as_ref()).await
248 }
249 }
250 }
251
252 #[inline]
253 async fn update_topic_subscribe_info(&self, topic: CheetahString, info: &HashSet<MessageQueue>) {
254 match &self.inner {
255 MQConsumerInnerImplKind::Push(consumer) => {
256 MQConsumerInner::update_topic_subscribe_info(consumer.as_ref(), topic, info).await
257 }
258 MQConsumerInnerImplKind::LitePull(consumer) => {
259 MQConsumerInner::update_topic_subscribe_info(consumer.as_ref(), topic, info).await
260 }
261 }
262 }
263
264 #[inline]
265 async fn is_subscribe_topic_need_update(&self, topic: &str) -> bool {
266 match &self.inner {
267 MQConsumerInnerImplKind::Push(consumer) => {
268 MQConsumerInner::is_subscribe_topic_need_update(consumer.as_ref(), topic).await
269 }
270 MQConsumerInnerImplKind::LitePull(consumer) => {
271 MQConsumerInner::is_subscribe_topic_need_update(consumer.as_ref(), topic).await
272 }
273 }
274 }
275
276 #[inline]
277 fn is_unit_mode(&self) -> bool {
278 match &self.inner {
279 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::is_unit_mode(consumer.as_ref()),
280 MQConsumerInnerImplKind::LitePull(consumer) => MQConsumerInner::is_unit_mode(consumer.as_ref()),
281 }
282 }
283
284 #[inline]
285 async fn reset_offsets(&self, topic: &CheetahString, offsets: HashMap<MessageQueue, i64>) {
286 match &self.inner {
287 MQConsumerInnerImplKind::Push(consumer) => {
288 MQConsumerInner::reset_offsets(consumer.as_ref(), topic, offsets).await
289 }
290 MQConsumerInnerImplKind::LitePull(consumer) => {
291 MQConsumerInner::reset_offsets(consumer.as_ref(), topic, offsets).await
292 }
293 }
294 }
295
296 #[inline]
297 async fn consumer_status(&self, topic: &CheetahString) -> HashMap<MessageQueue, i64> {
298 match &self.inner {
299 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::consumer_status(consumer.as_ref(), topic).await,
300 MQConsumerInnerImplKind::LitePull(consumer) => {
301 MQConsumerInner::consumer_status(consumer.as_ref(), topic).await
302 }
303 }
304 }
305
306 #[inline]
307 async fn consumer_running_info(&self) -> ConsumerRunningInfo {
308 match &self.inner {
309 MQConsumerInnerImplKind::Push(consumer) => MQConsumerInner::consumer_running_info(consumer.as_ref()).await,
310 MQConsumerInnerImplKind::LitePull(consumer) => {
311 MQConsumerInner::consumer_running_info(consumer.as_ref()).await
312 }
313 }
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use rocketmq_protocol::protocol::heartbeat::consume_type::ConsumeType;
320
321 use super::*;
322 use crate::base::client_config::ClientConfig;
323 use crate::consumer::consumer_impl::default_lite_pull_consumer_impl::LitePullConsumerConfig;
324
325 #[test]
326 fn lite_pull_wrapper_delegates_heartbeat_fields() {
327 let consumer_group = CheetahString::from_static_str("lite_pull_wrapper_group");
328 let consumer_config = Arc::new(LitePullConsumerConfig {
329 consumer_group: consumer_group.clone(),
330 ..Default::default()
331 });
332 let impl_ = Arc::new(DefaultLitePullConsumerImpl::new(
333 crate::runtime::test_client_runtime("mq-consumer-inner-test"),
334 Arc::new(ClientConfig::default()),
335 consumer_config,
336 ));
337 let wrapper = MQConsumerInnerImpl::from_lite_pull(impl_);
338
339 assert_eq!(MQConsumerInner::group_name(&wrapper), consumer_group);
340 assert_eq!(MQConsumerInner::message_model(&wrapper), MessageModel::Clustering);
341 assert_eq!(MQConsumerInner::consume_type(&wrapper), ConsumeType::ConsumeActively);
342 assert_eq!(
343 MQConsumerInner::consume_from_where(&wrapper),
344 ConsumeFromWhere::ConsumeFromLastOffset
345 );
346 assert!(!MQConsumerInner::is_unit_mode(&wrapper));
347 assert!(MQConsumerInner::subscriptions(&wrapper).is_empty());
348 }
349}