[ISSUE #380] Fix NOT_CONSUME_YET false positive in message track detail#424
Open
messere1 wants to merge 3 commits into
Open
[ISSUE #380] Fix NOT_CONSUME_YET false positive in message track detail#424messere1 wants to merge 3 commits into
messere1 wants to merge 3 commits into
Conversation
…k detail The messageTrackDetail() method delegates to DefaultMQAdminExtImpl.consumed() which requires an exact broker-address match between msg.getStoreHost() and the broker's registered address. When the broker registers with a hostname (or when DNS resolution inside the dashboard container differs from the broker), the address comparison silently fails and every message is incorrectly reported as NOT_CONSUME_YET even though it has already been consumed. This patch adds a fallback verification in MessageServiceImpl: when a track is marked NOT_CONSUME_YET, it re-checks the consumer offset directly via examineConsumeStats, matching only on topic + queueId + offset and skipping the fragile address comparison. If the consumer offset has advanced past the message's queue offset, the track type is corrected to CONSUMED.
There was a problem hiding this comment.
Pull request overview
This PR fixes a RocketMQ Dashboard UI false-positive where already-consumed messages can be shown as NOT_CONSUME_YET in the message track detail view by adding a fallback verification that checks consumer offsets via examineConsumeStats when the admin API reports NOT_CONSUME_YET.
Changes:
- Post-process
messageTrackDetail()results to re-verifyNOT_CONSUME_YETtracks using consumer offsets (avoiding broker-address equality pitfalls). - Add unit tests covering correction behavior, non-correction cases, and exception handling during fallback.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/main/java/org/apache/rocketmq/dashboard/service/impl/MessageServiceImpl.java | Adds fallback consumption verification for NOT_CONSUME_YET tracks using examineConsumeStats. |
| src/test/java/org/apache/rocketmq/dashboard/service/impl/MessageServiceImplTest.java | Adds unit tests validating the new fallback logic and its failure behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…level stats cache - Add resolveBrokerName() to match message storeHost against topic route data, preventing cross-broker false positives when multiple brokers share same topic+queueId - Change isConsumedByGroup() to accept ConsumeStats instead of group name, filtering MessageQueue by brokerName+topic+queueId for precise offset comparison - Add group-level ConsumeStats cache via computeIfAbsent to avoid redundant RPC calls - Return false (conservative) when brokerName cannot be resolved - Add 3 new test cases: cross-broker no-false-positive, unresolvable brokerName, and group-level cache verification
messere1
force-pushed
the
contest/bugfix-pr07-not-consume-yet
branch
from
July 8, 2026 12:16
cafa441 to
441ed79
Compare
…ismatch scenarios When topic route data contains only one broker, skip IP-level address matching and directly adopt that brokerName. This covers the most common deployment (dev/test/small prod) where DNS/hostname differences between broker registration and dashboard JVM cause resolveBrokerName to fail silently — the exact root cause of issue apache#380. - resolveBrokerName: early return when brokerDatas.size() == 1 - New test: SingleBrokerShortCircuitWithMismatchedIp verifies that a single broker with non-matching hostname still resolves correctly - Updated test: BrokerNameUnresolvable now uses multi-broker route data to properly test the conservative fallback path
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the purpose of the change
Fix #380: Messages that have already been consumed are incorrectly displayed as
NOT_CONSUME_YETin the message track detail page.Root Cause
MessageServiceImpl.messageTrackDetail()delegates toDefaultMQAdminExtImpl.consumed()which determines whether a message has been consumed by comparing the consumer offset against the message's queue offset. However,consumed()also requires an exact broker-address match betweenmsg.getStoreHost()and the broker's registered address:When the broker registers with a hostname (e.g.
broker-a:10911) and the DNS resolution inside the dashboard JVM differs from the broker's environment,convert2IpStringproduces a different IP string thansocketAddress2String(msg.getStoreHost()), causing the address comparison to silently fail. As a result,consumed()returnsfalseand the message is reported asNOT_CONSUME_YETeven though the consumer offset has already advanced past the message.A community member also confirmed in the issue: "用控制台创建消费者组 消费状态就正常了" — suggesting the address-matching path is sensitive to how the consumer group and broker are configured.
Fix
Initial fix (commit 1)
Add a fallback verification in
MessageServiceImpl.messageTrackDetail(): when the underlying admin API returnsNOT_CONSUME_YET, re-check the consumer offset directly viaexamineConsumeStats, matching on topic + queueId + offset and skipping the fragile broker-address comparison. If the consumer offset has advanced past the message's queue offset, the track type is corrected toCONSUMED.Hardening (commit 2 — multi-broker correctness)
After further analysis, the initial fix had a subtle flaw: matching only on
topic + queueIdis insufficient in multi-broker clusters where broker-a and broker-b both have a queue with the same queueId but independent offsets. This could cause a cross-broker false positive if the wrong broker's offset happened to be higher.The hardening introduces two improvements:
Broker-level address resolution (
resolveBrokerName()): Instead of blindly matching all queues with the same topic+queueId, the method now resolves which broker actually holds the message by comparingmsg.getStoreHost()against topic route data at the IP level. Only the MessageQueue whosebrokerNamematches the resolved broker is considered for offset comparison. If brokerName cannot be resolved (e.g. route data unavailable), the method conservatively returnsfalse— preserving the originalNOT_CONSUME_YETrather than risking a false positive.Group-level ConsumeStats cache: When multiple
NOT_CONSUME_YETtracks belong to the same consumer group,examineConsumeStatsis now called only once per group (viacomputeIfAbsent), eliminating redundant RPC calls.Single-broker short-circuit (commit 3 — DNS/hostname resilience)
The IP-level matching in
resolveBrokerName()can still fail in NAT/container environments where DNS resolution differs between the dashboard JVM and the broker. However, single-broker deployments — the most common scenario for issue #380 (dev/test/small-scale prod) — can be handled with zero ambiguity: if there is only one broker in the route data, that broker holds the message by definition.The short-circuit checks
brokerDatas.size() == 1before attempting IP matching, and directly returns the sole brokerName. This makes the fix effective even in the most pathological DNS/hostname mismatch scenarios, with no risk of cross-broker confusion.The fallback remains:
NOT_CONSUME_YET→CONSUMED, never the reverse.examineConsumeStatsthrows orresolveBrokerNamefails, the originalNOT_CONSUME_YETis preserved.Brief changelog
MessageServiceImpl.java:messageTrackDetail(): post-processNOT_CONSUME_YETtracks viaexamineConsumeStatswith group-level cache.isConsumedByGroup(MessageExt, ConsumeStats): signature changed to accept pre-fetched stats; now filters MessageQueue bybrokerName + topic + queueId.resolveBrokerName(MessageExt): new method — resolves broker name via topic route data + IP-level matching, with single-broker short-circuit.MessageServiceImplTest.java: 9 unit tests covering the fallback logic.Verifying this change
Unit tests added (
MessageServiceImplTest):testMessageTrackDetail_NotConsumeYetCorrectedToConsumed— NOT_CONSUME_YET with consumerOffset > queueOffset → corrected to CONSUMEDtestMessageTrackDetail_NotConsumeYetRemainsWhenNotConsumed— NOT_CONSUME_YET with consumerOffset < queueOffset → remains NOT_CONSUME_YETtestMessageTrackDetail_CrossBrokerNoFalsePositive— multi-broker route, msg on broker-a, broker-b has same topic+queueId with higher offset → stays NOT_CONSUME_YET (no cross-broker match)testMessageTrackDetail_BrokerNameUnresolvableStaysNotConsumeYet— multi-broker route, no broker IP matches → stays NOT_CONSUME_YET (conservative fallback)testMessageTrackDetail_ConsumedTrackUnchanged— CONSUMED track is not re-verifiedtestMessageTrackDetail_NotOnlineTrackUnchanged— NOT_ONLINE track is not re-verifiedtestMessageTrackDetail_ExamineConsumeStatsThrowsException— when examineConsumeStats throws, original NOT_CONSUME_YET is preservedtestMessageTrackDetail_GroupLevelStatsCache— two NOT_CONSUME_YET tracks with same group → examineConsumeStats called only oncetestMessageTrackDetail_SingleBrokerShortCircuitWithMismatchedIp— single broker with non-matching hostname → short-circuit resolves brokerName, corrected to CONSUMEDAll 24 tests in
MessageServiceImplTestpass.[ISSUE #380] Fix NOT_CONSUME_YET false positive in message track detail.mvn clean install -DskipITsto make sure unit-test pass.