Skip to content

[ISSUE #6608]šŸš€Implement topic unsubscription and message queue removal in DefaultLitePullConsumerImpl#6609

Merged
rocketmq-rust-bot merged 1 commit intomainfrom
feat-6608
Mar 1, 2026
Merged

[ISSUE #6608]šŸš€Implement topic unsubscription and message queue removal in DefaultLitePullConsumerImpl#6609
rocketmq-rust-bot merged 1 commit intomainfrom
feat-6608

Conversation

@mxsm
Copy link
Owner

@mxsm mxsm commented Mar 1, 2026

Which Issue(s) This PR Fixes(Closes)

Brief Description

How Did You Test This Change?

Summary by CodeRabbit

  • New Features
    • Topic unsubscription with automatic termination and cleanup of associated resources
    • Timestamp-based offset search capability for message queues
    • Message queue discovery and retrieval for topics, including namespace handling
    • Foundation prepared for additional offset-related consumer operations

@rocketmq-rust-bot
Copy link
Collaborator

šŸ”Š@mxsm šŸš€Thanks for your contributionšŸŽ‰ļ¼

šŸ’”CodeRabbit(AI) will review your code firstšŸ”„ļ¼

Note

🚨The code review suggestions from CodeRabbit are to be used as a reference only, and the PR submitter can decide whether to make changes based on their own judgment. Ultimately, the project management personnel will conduct the final code reviewšŸ’„.

@rocketmq-rust-robot rocketmq-rust-robot added the featurešŸš€ Suggest an idea for this project. label Mar 1, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 1, 2026

Walkthrough

This pull request adds topic unsubscription and message queue removal capabilities to the RocketMQ lite pull consumer. It introduces a new remove_by_topic method to the queue assignment manager and expands the consumer implementation with topic-based queue discovery, unsubscription, offset searching, and several placeholder methods for future offset management operations.

Changes

Cohort / File(s) Summary
Queue Removal
rocketmq-client/src/consumer/consumer_impl/assigned_message_queue.rs
Added async remove_by_topic() method that acquires write lock, filters out queues matching the given topic, marks them as dropped, and returns the removed process queues as a vector.
Topic Unsubscription & Queue Discovery
rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs
Added unsubscribe() to remove topics and terminate pull tasks; search_offset() to query broker for timestamp-based offsets; fetch_message_queues() to retrieve topic routes from name server and strip namespace; parse_message_queues() helper for namespace stripping; plus placeholder stubs for offset operations (offset_for_timestamp, earliest_msg_store_time, max_offset_public, min_offset_public) and utility methods (update_name_server_address, is_auto_commit).

Sequence Diagram

sequenceDiagram
    participant Client as Consumer Client
    participant Consumer as DefaultLitePullConsumerImpl
    participant TaskMgr as PullTaskManager
    participant Queue as AssignedMessageQueue
    participant NS as NameServer/Router

    Client->>Consumer: unsubscribe(topic)
    Consumer->>TaskMgr: terminate_pull_task(topic)
    TaskMgr->>TaskMgr: stop & remove tasks
    Consumer->>Consumer: remove subscribed topic
    Consumer->>Queue: remove_by_topic(topic)
    Queue->>Queue: acquire write lock
    Queue->>Queue: filter & drop queues
    Queue-->>Consumer: Vec<ProcessQueue>
    Consumer-->>Client: Result<()>

    Client->>Consumer: fetch_message_queues(topic)
    Consumer->>NS: fetch topic route
    NS-->>Consumer: MessageQueue set
    Consumer->>Consumer: parse_message_queues()
    Consumer->>Consumer: strip namespace
    Consumer-->>Client: HashSet<MessageQueue>

    Client->>Consumer: search_offset(mq, timestamp)
    Consumer->>NS: query offset for timestamp
    NS-->>Consumer: i64 offset
    Consumer-->>Client: RocketMQResult<i64>
Loading

Estimated code review effort

šŸŽÆ 3 (Moderate) | ā±ļø ~22 minutes

Possibly related PRs

Suggested labels

AI review first

Suggested reviewers

  • SpaceXCN
  • TeslaRustor
  • rocketmq-rust-bot

Poem

🐰 Topics hop away, no longer to stay,
Queues dance their final ballet,
Offsets now searchable, subscriptions so clear,
The consumer grows stronger, year after year! ✨

🚄 Pre-merge checks | āœ… 5
āœ… Passed checks (5 passed)
Check name Status Explanation
Description Check āœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check āœ… Passed The title clearly summarizes the main changes: implementing topic unsubscription and message queue removal in DefaultLitePullConsumerImpl, which directly matches the PR's core changes.
Linked Issues check āœ… Passed The PR successfully implements the stated objective of adding topic unsubscription and message queue removal functionality to DefaultLitePullConsumerImpl as required by issue #6608.
Out of Scope Changes check āœ… Passed All changes are scoped to the stated objective: unsubscribe method for topics, message queue removal support, and related helper methods for queue discovery and offset operations.
Docstring Coverage āœ… Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

āœļø Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • šŸ“ Generate docstrings (stacked PR)
  • šŸ“ Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-6608

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

ā¤ļø Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs (2)

1219-1229: Doc comment inconsistent with implementation.

The documentation states "This is an alias for search_offset" but the implementation uses todo!() instead of delegating. If this is meant to be an alias, consider delegating to search_offset.

šŸ”§ Proposed fix to match documentation
 #[allow(dead_code)]
 pub async fn offset_for_timestamp(&self, _mq: &MessageQueue, _timestamp: u64) -> RocketMQResult<i64> {
-    todo!("offset_for_timestamp: Low priority method, not yet implemented")
+    self.search_offset(_mq, _timestamp).await
 }
šŸ¤– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs`
around lines 1219 - 1229, The doc says offset_for_timestamp is an alias for
search_offset but the impl uses todo!(); change pub async fn
offset_for_timestamp(&self, _mq: &MessageQueue, _timestamp: u64) ->
RocketMQResult<i64> to delegate to the existing async search_offset method (call
self.search_offset(mq, timestamp).await and return its result), removing the
todo!() and using the same parameter names (mq, timestamp) to match
search_offset's signature and propagate its RocketMQResult<i64>.

1273-1281: is_auto_commit can be trivially implemented.

This method has a straightforward implementation available - simply return the config value. Consider implementing it instead of using todo!() to avoid potential runtime panics.

šŸ”§ Proposed implementation
 #[allow(dead_code)]
 pub fn is_auto_commit(&self) -> bool {
-    todo!("is_auto_commit: Low priority method, not yet implemented")
+    self.consumer_config.auto_commit
 }
šŸ¤– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs`
around lines 1273 - 1281, Replace the todo! in the is_auto_commit(&self) -> bool
method with a direct return of the configured value (e.g., return the boolean
from the consumer's config such as self.config.auto_commit or by calling a
config getter like self.config.is_auto_commit()). Update the implementation of
is_auto_commit to simply read and return that config flag instead of panicking.
šŸ¤– Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs`:
- Around line 1107-1135: The unsubscribe method removes local subscription state
but doesn't notify brokers like subscribe does; after removing the topic from
rebalance_impl, stopping tasks, and clearing assigned_message_queue in
unsubscribe, invoke the same broker-notify logic used by subscribe (e.g. call
the rebalance_impl send-heartbeat method such as send_heartbeat_to_all_brokers
or equivalent) when the consumer is running (check the consumer running flag
used in subscribe) and await/handle its result (log errors if the heartbeat
fails) so brokers receive the unsubscription update.

---

Nitpick comments:
In
`@rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs`:
- Around line 1219-1229: The doc says offset_for_timestamp is an alias for
search_offset but the impl uses todo!(); change pub async fn
offset_for_timestamp(&self, _mq: &MessageQueue, _timestamp: u64) ->
RocketMQResult<i64> to delegate to the existing async search_offset method (call
self.search_offset(mq, timestamp).await and return its result), removing the
todo!() and using the same parameter names (mq, timestamp) to match
search_offset's signature and propagate its RocketMQResult<i64>.
- Around line 1273-1281: Replace the todo! in the is_auto_commit(&self) -> bool
method with a direct return of the configured value (e.g., return the boolean
from the consumer's config such as self.config.auto_commit or by calling a
config getter like self.config.is_auto_commit()). Update the implementation of
is_auto_commit to simply read and return that config flag instead of panicking.

ā„¹ļø Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

šŸ“„ Commits

Reviewing files that changed from the base of the PR and between 1bb0465 and d117cb8.

šŸ“’ Files selected for processing (2)
  • rocketmq-client/src/consumer/consumer_impl/assigned_message_queue.rs
  • rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs

Comment on lines +1107 to +1135
/// Unsubscribes from the specified topic.
///
/// Removes the topic subscription, stops and removes all pull tasks for the topic,
/// and clears assigned message queues for the topic.
///
/// This operation can be performed regardless of the consumer state.
pub async fn unsubscribe(&mut self, topic: impl Into<CheetahString>) -> RocketMQResult<()> {
let topic = topic.into();

// Remove from rebalance_impl subscription
self.rebalance_impl.get_subscription_inner().remove(&topic);

// Stop and remove pull tasks for this topic
let mut task_handles = self.task_handles.write().await;
task_handles.retain(|mq, handle| {
if mq.topic() == topic.as_str() {
handle.abort();
false
} else {
true
}
});
drop(task_handles);

// Remove from assigned_message_queue
self.assigned_message_queue.remove_by_topic(topic.as_str()).await;

Ok(())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

āš ļø Potential issue | 🟠 Major

Consider notifying brokers of unsubscription.

The subscribe method (lines 393-398) sends a heartbeat to all brokers when running to notify them of the subscription change. However, unsubscribe does not notify brokers that the subscription was removed. This could leave stale subscription data on brokers until the next scheduled heartbeat.

šŸ› ļø Proposed fix to add heartbeat notification
     // Remove from assigned_message_queue
     self.assigned_message_queue.remove_by_topic(topic.as_str()).await;

+    // Notify brokers of subscription change if running
+    if *self.service_state == ServiceState::Running {
+        if let Some(ref client_instance) = self.client_instance {
+            client_instance.send_heartbeat_to_all_broker_with_lock().await;
+        }
+    }
+
     Ok(())
 }
šŸ“ Committable suggestion

ā€¼ļø IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Unsubscribes from the specified topic.
///
/// Removes the topic subscription, stops and removes all pull tasks for the topic,
/// and clears assigned message queues for the topic.
///
/// This operation can be performed regardless of the consumer state.
pub async fn unsubscribe(&mut self, topic: impl Into<CheetahString>) -> RocketMQResult<()> {
let topic = topic.into();
// Remove from rebalance_impl subscription
self.rebalance_impl.get_subscription_inner().remove(&topic);
// Stop and remove pull tasks for this topic
let mut task_handles = self.task_handles.write().await;
task_handles.retain(|mq, handle| {
if mq.topic() == topic.as_str() {
handle.abort();
false
} else {
true
}
});
drop(task_handles);
// Remove from assigned_message_queue
self.assigned_message_queue.remove_by_topic(topic.as_str()).await;
Ok(())
}
/// Unsubscribes from the specified topic.
///
/// Removes the topic subscription, stops and removes all pull tasks for the topic,
/// and clears assigned message queues for the topic.
///
/// This operation can be performed regardless of the consumer state.
pub async fn unsubscribe(&mut self, topic: impl Into<CheetahString>) -> RocketMQResult<()> {
let topic = topic.into();
// Remove from rebalance_impl subscription
self.rebalance_impl.get_subscription_inner().remove(&topic);
// Stop and remove pull tasks for this topic
let mut task_handles = self.task_handles.write().await;
task_handles.retain(|mq, handle| {
if mq.topic() == topic.as_str() {
handle.abort();
false
} else {
true
}
});
drop(task_handles);
// Remove from assigned_message_queue
self.assigned_message_queue.remove_by_topic(topic.as_str()).await;
// Notify brokers of subscription change if running
if *self.service_state == ServiceState::Running {
if let Some(ref client_instance) = self.client_instance {
client_instance.send_heartbeat_to_all_broker_with_lock().await;
}
}
Ok(())
}
šŸ¤– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs`
around lines 1107 - 1135, The unsubscribe method removes local subscription
state but doesn't notify brokers like subscribe does; after removing the topic
from rebalance_impl, stopping tasks, and clearing assigned_message_queue in
unsubscribe, invoke the same broker-notify logic used by subscribe (e.g. call
the rebalance_impl send-heartbeat method such as send_heartbeat_to_all_brokers
or equivalent) when the consumer is running (check the consumer running flag
used in subscribe) and await/handle its result (log errors if the heartbeat
fails) so brokers receive the unsubscription update.

@codecov
Copy link

codecov bot commented Mar 1, 2026

Codecov Report

āŒ Patch coverage is 0% with 85 lines in your changes missing coverage. Please review.
āœ… Project coverage is 41.54%. Comparing base (1bb0465) to head (d117cb8).
āš ļø Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...r/consumer_impl/default_lite_pull_consumer_impl.rs 0.00% 73 Missing āš ļø
...c/consumer/consumer_impl/assigned_message_queue.rs 0.00% 12 Missing āš ļø
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6609      +/-   ##
==========================================
- Coverage   41.56%   41.54%   -0.03%     
==========================================
  Files         959      959              
  Lines      134490   134575      +85     
==========================================
  Hits        55907    55907              
- Misses      78583    78668      +85     

ā˜” View full report in Codecov by Sentry.
šŸ“¢ Have feedback on the report? Share it here.

šŸš€ New features to boost your workflow:
  • ā„ļø Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • šŸ“¦ JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Collaborator

@rocketmq-rust-bot rocketmq-rust-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - All CI checks passed āœ…

@rocketmq-rust-bot rocketmq-rust-bot merged commit fbac39a into main Mar 1, 2026
18 of 20 checks passed
@rocketmq-rust-bot rocketmq-rust-bot added approved PR has approved and removed ready to review waiting-review waiting review this PR labels Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI review first Ai review pr first approved PR has approved auto merge featurešŸš€ Suggest an idea for this project.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FeaturešŸš€] Implement topic unsubscription and message queue removal in DefaultLitePullConsumerImpl

3 participants