Skip to content

[ISSUE #6605]🚀Add consume message hooks and topic namespace handling in DefaultLitePullConsumerImpl#6606

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

[ISSUE #6605]🚀Add consume message hooks and topic namespace handling in DefaultLitePullConsumerImpl#6606
rocketmq-rust-bot merged 1 commit intomainfrom
feat-6605

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
    • Added ability to register consume message hooks for before/after consumption processing events
    • Implemented automatic topic namespace normalization for message handling

@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 change adds consume message hooks support to the DefaultLitePullConsumerImpl, enabling hook execution before and after message consumption with panic protection. It also introduces namespace stripping for messages via a reset_topic method to normalize topic names by removing configured namespace prefixes.

Changes

Cohort / File(s) Summary
Consume Message Hooks & Namespace Handling
rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs
Adds public API register_consume_message_hook() for hook registration, implements ConsumeMessageContext construction and hook execution before/after message consumption with panic protection and per-hook error logging, introduces private reset_topic() helper for namespace stripping, and imports NamespaceUtil and ConsumeMessageContext to support the new functionality.

Sequence Diagram(s)

sequenceDiagram
    participant Consumer as DefaultLitePullConsumerImpl
    participant Hooks as Registered Hooks
    participant Context as ConsumeMessageContext
    participant Handler as Message Handler

    Consumer->>Consumer: poll() or consume
    Consumer->>Consumer: Reset topics via reset_topic()
    Consumer->>Context: Create ConsumeMessageContext
    Consumer->>Hooks: Execute before_consume hook
    Note over Hooks: With panic protection (catch_unwind)
    Hooks-->>Consumer: Hook completed (log errors if any)
    Consumer->>Handler: Process messages
    Handler-->>Consumer: Processing complete
    Consumer->>Hooks: Execute after_consume hook
    Note over Hooks: With panic protection (catch_unwind)
    Hooks-->>Consumer: Hook completed (log errors if any)
    Consumer-->>Consumer: Return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With hooks now woven through the thread,
Messages bloom in namespaces spread,
Before and after, we guard with care,
No panic shall freeze us in mid-air! 🌿
DefaultLitePull now hops with delight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The PR implements the feature stated in issue #6605 (consume message hooks and topic namespace handling), but the issue lacks detailed requirements making full compliance validation inconclusive. The linked issue #6605 provides only a feature title with no detailed requirements. Verify that the implementation of hooks and namespace handling meets all intended functionality and design specifications.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main changes: adding consume message hooks and topic namespace handling to DefaultLitePullConsumerImpl, matching the actual implementation.
Out of Scope Changes check ✅ Passed All changes are focused on adding consume message hooks and namespace handling to DefaultLitePullConsumerImpl, staying within the scope of the stated feature objective.
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-6605

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 (1)
rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs (1)

955-969: Avoid per-message allocation in reset_topic hot path.

Line 964 allocates a new String for every message. You can use a borrowed &str and only call set_topic when the value actually changes.

Refactor sketch
-                for msg in messages.iter_mut() {
-                    let topic = msg.message.topic().to_string();
-                    let topic_without_namespace =
-                        NamespaceUtil::without_namespace_with_namespace(&topic, namespace.as_str());
-                    msg.message
-                        .set_topic(CheetahString::from_string(topic_without_namespace));
-                }
+                for msg in messages.iter_mut() {
+                    let current_topic = msg.message.topic();
+                    let topic_without_namespace = NamespaceUtil::without_namespace_with_namespace(
+                        current_topic.as_str(),
+                        namespace.as_str(),
+                    );
+                    if topic_without_namespace != current_topic.as_str() {
+                        msg.message
+                            .set_topic(CheetahString::from_string(topic_without_namespace));
+                    }
+                }
🤖 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 955 - 969, In reset_topic, avoid allocating a new String per
message: obtain the topic as a &str (via msg.message.topic()) instead of calling
to_string(), call NamespaceUtil::without_namespace_with_namespace with that &str
and the namespace, compare the returned value to the original topic and only
call msg.message.set_topic(...) when the topic actually changed; construct a
CheetahString (e.g. from_string or from_str) only in the branch where set_topic
is needed so allocations happen only on changed topics. Use the existing symbols
reset_topic, ArcMut<MessageExt>,
NamespaceUtil::without_namespace_with_namespace, and
msg.message.set_topic/CheetahString when applying the change.
🤖 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 801-809: The panic guards around hook execution are incomplete
because hook.hook_name() is invoked outside the catch_unwind blocks; if
hook_name() panics it will still unwind poll(). Wrap both the hook call and any
inspection of the hook (including hook.hook_name()) inside the
std::panic::catch_unwind boundaries for the before and after paths (the loops
over self.consume_message_hook_list where hook.consume_message_before /
hook.consume_message_after are invoked), and log the hook name only from within
the catch_unwind success branch or capture it beforehand using a panic-safe
string (e.g., call hook_name inside the same AssertUnwindSafe closure or derive
a debug name via a provided safe accessor) so no code outside the catch_unwind
can panic.

---

Nitpick comments:
In
`@rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs`:
- Around line 955-969: In reset_topic, avoid allocating a new String per
message: obtain the topic as a &str (via msg.message.topic()) instead of calling
to_string(), call NamespaceUtil::without_namespace_with_namespace with that &str
and the namespace, compare the returned value to the original topic and only
call msg.message.set_topic(...) when the topic actually changed; construct a
CheetahString (e.g. from_string or from_str) only in the branch where set_topic
is needed so allocations happen only on changed topics. Use the existing symbols
reset_topic, ArcMut<MessageExt>,
NamespaceUtil::without_namespace_with_namespace, and
msg.message.set_topic/CheetahString when applying the change.

ℹ️ 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 9cfae92 and d7926b0.

📒 Files selected for processing (1)
  • rocketmq-client/src/consumer/consumer_impl/default_lite_pull_consumer_impl.rs

Comment on lines +801 to +809
for hook in &self.consume_message_hook_list {
if let Err(err) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
hook.consume_message_before(Some(&mut context));
})) {
tracing::error!(
"consumeMessageHook {} executeHookBefore panicked: {:?}",
hook.hook_name(),
err
);
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 | 🟡 Minor

Panic isolation is incomplete in the hook error path.

On Line 806 and Line 823, hook.hook_name() is called outside catch_unwind. If hook_name() itself panics, poll() can still unwind despite the panic guards.

Suggested hardening
-                for hook in &self.consume_message_hook_list {
+                for (idx, hook) in self.consume_message_hook_list.iter().enumerate() {
                     if let Err(err) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                         hook.consume_message_before(Some(&mut context));
                     })) {
                         tracing::error!(
-                            "consumeMessageHook {} executeHookBefore panicked: {:?}",
-                            hook.hook_name(),
+                            "consumeMessageHook[{}] executeHookBefore panicked: {:?}",
+                            idx,
                             err
                         );
                     }
                 }
@@
-                for hook in &self.consume_message_hook_list {
+                for (idx, hook) in self.consume_message_hook_list.iter().enumerate() {
                     if let Err(err) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                         hook.consume_message_after(Some(&mut context));
                     })) {
                         tracing::error!(
-                            "consumeMessageHook {} executeHookAfter panicked: {:?}",
-                            hook.hook_name(),
+                            "consumeMessageHook[{}] executeHookAfter panicked: {:?}",
+                            idx,
                             err
                         );
                     }
                 }

Also applies to: 819-826

🤖 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 801 - 809, The panic guards around hook execution are incomplete
because hook.hook_name() is invoked outside the catch_unwind blocks; if
hook_name() panics it will still unwind poll(). Wrap both the hook call and any
inspection of the hook (including hook.hook_name()) inside the
std::panic::catch_unwind boundaries for the before and after paths (the loops
over self.consume_message_hook_list where hook.consume_message_before /
hook.consume_message_after are invoked), and log the hook name only from within
the catch_unwind success branch or capture it beforehand using a panic-safe
string (e.g., call hook_name inside the same AssertUnwindSafe closure or derive
a debug name via a provided safe accessor) so no code outside the catch_unwind
can panic.

@codecov
Copy link

codecov bot commented Mar 1, 2026

Codecov Report

❌ Patch coverage is 0% with 47 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.57%. Comparing base (9cfae92) to head (d7926b0).
⚠️ 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% 47 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6606      +/-   ##
==========================================
- Coverage   41.58%   41.57%   -0.02%     
==========================================
  Files         959      959              
  Lines      134446   134490      +44     
==========================================
+ Hits        55907    55908       +1     
- Misses      78539    78582      +43     

☔ 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 1bb0465 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🚀] Add consume message hooks and topic namespace handling in DefaultLitePullConsumerImpl

3 participants