This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new aae11ff0d fix(lite): surface session metric read failures (#4536)
aae11ff0d is described below

commit aae11ff0da98b1f51eb23e4180740bb90cebddda
Author: zmuxuny <[email protected]>
AuthorDate: Mon Sep 21 21:01:36 2026 +0800

    fix(lite): surface session metric read failures (#4536)
    
    `RocketMQLiteTopicProvider.getSession` folded broker metric failures into 
zeros. The backlog came from `groupLag`, which swallowed a failed 
`getLiteGroupInfo` into `0`, and `consumedMessages` logged each per-LiteTopic 
offset read failure at debug and skipped the topic. A session whose master was 
unreachable therefore rendered as a healthy group with no pending messages, on 
the one screen where the operator explicitly asked for that group's numbers.
    
    The session path now reads its backlog through a new `sessionGroupLag` that 
throws `BusinessException(502)` when the call fails or returns no body, and a 
failed offset read throws instead of being skipped; `InterruptedException` 
restores the interrupt flag before the rethrow. The best-effort `groupLag` is 
left in place for the list and summary paths, where one unreadable group must 
not take the whole page down.
    
    Fixes #4535
---
 .../provider/apache/RocketMQLiteTopicProvider.java | 29 ++++++++++-
 .../apache/RocketMQLiteTopicProviderTest.java      | 58 ++++++++++++++++++++++
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProvider.java
index f86f69a80..f7b160744 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProvider.java
@@ -275,7 +275,7 @@ public class RocketMQLiteTopicProvider implements 
LiteTopicProvider {
                 .toList();
         session.setLiteTopics(new LinkedHashSet<>(liteTopics));
 
-        long pending = groupLag(admin, located.master, group);
+        long pending = sessionGroupLag(admin, located.master, group);
         long consumed = consumedMessages(admin, located.master, group, 
liteTopics);
         session.setPendingMessages(pending);
         session.setConsumedMessages(consumed);
@@ -317,7 +317,10 @@ public class RocketMQLiteTopicProvider implements 
LiteTopicProvider {
                     consumed += wrapper.getConsumerOffset();
                 }
             } catch (Exception failure) {
-                log.debug("Failed to read lite offset for {}|{}: {}", group, 
liteTopic, failure.getMessage());
+                restoreInterrupt(failure);
+                throw new BusinessException(502,
+                        "Failed to read LiteTopic consumed offset for " + 
group + "|" + liteTopic
+                                + ": " + failure.getMessage());
             }
         }
         return consumed;
@@ -521,6 +524,28 @@ public class RocketMQLiteTopicProvider implements 
LiteTopicProvider {
         return null;
     }
 
+    private long sessionGroupLag(MQAdminExt admin, String brokerAddr, String 
group) {
+        try {
+            GetLiteGroupInfoResponseBody body = 
admin.getLiteGroupInfo(brokerAddr, group, null, 1);
+            if (body == null) {
+                throw new BusinessException(502, "Broker returned no LiteTopic 
backlog for group " + group);
+            }
+            return Math.max(body.getTotalLagCount(), 0);
+        } catch (BusinessException failure) {
+            throw failure;
+        } catch (Exception failure) {
+            restoreInterrupt(failure);
+            throw new BusinessException(502,
+                    "Failed to read LiteTopic backlog for group " + group + ": 
" + failure.getMessage());
+        }
+    }
+
+    private static void restoreInterrupt(Exception failure) {
+        if (failure instanceof InterruptedException) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
     private long groupLag(MQAdminExt admin, String brokerAddr, String group) {
         try {
             GetLiteGroupInfoResponseBody body = 
admin.getLiteGroupInfo(brokerAddr, group, null, 1);
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProviderTest.java
index 58f234e3b..0fbf4c004 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQLiteTopicProviderTest.java
@@ -184,6 +184,64 @@ class RocketMQLiteTopicProviderTest {
         assertThat(session.getTotalMessages()).isEqualTo(15L);
     }
 
+    @Test
+    void getSessionShouldSurfaceBacklogReadFailureTest() throws Exception {
+        when(admin.examineBrokerClusterInfo()).thenReturn(cluster(BROKER_A));
+        when(admin.getLiteClientInfo(BROKER_A, PARENT, GROUP, "c1"))
+                .thenReturn(clientInfo(1, System.currentTimeMillis(), 
LiteUtil.toLmqName(PARENT, "bob")));
+        when(admin.getLiteGroupInfo(BROKER_A, GROUP, null, 1))
+                .thenThrow(new IllegalStateException("backlog unavailable"));
+
+        assertThatThrownBy(() -> provider.getSession(
+                RocketMQLiteTopicProvider.encodeSessionId(PARENT, GROUP, 
"c1")))
+                .isInstanceOfSatisfying(BusinessException.class,
+                        ex -> assertThat(ex.getCode()).isEqualTo(502));
+    }
+
+    @Test
+    void getSessionShouldSurfaceConsumedOffsetReadFailureTest() throws 
Exception {
+        when(admin.examineBrokerClusterInfo()).thenReturn(cluster(BROKER_A));
+        when(admin.getLiteClientInfo(BROKER_A, PARENT, GROUP, "c1"))
+                .thenReturn(clientInfo(1, System.currentTimeMillis(), 
LiteUtil.toLmqName(PARENT, "bob")));
+        when(admin.getLiteGroupInfo(BROKER_A, GROUP, null, 
1)).thenReturn(lag(5));
+        when(admin.getLiteGroupInfo(BROKER_A, GROUP, "bob", 1))
+                .thenThrow(new IllegalStateException("offset unavailable"));
+
+        assertThatThrownBy(() -> provider.getSession(
+                RocketMQLiteTopicProvider.encodeSessionId(PARENT, GROUP, 
"c1")))
+                .isInstanceOfSatisfying(BusinessException.class,
+                        ex -> assertThat(ex.getCode()).isEqualTo(502));
+    }
+
+    @Test
+    void getSessionShouldRejectMissingBacklogBodyTest() throws Exception {
+        when(admin.examineBrokerClusterInfo()).thenReturn(cluster(BROKER_A));
+        when(admin.getLiteClientInfo(BROKER_A, PARENT, GROUP, "c1"))
+                .thenReturn(clientInfo(0, System.currentTimeMillis()));
+
+        assertThatThrownBy(() -> provider.getSession(
+                RocketMQLiteTopicProvider.encodeSessionId(PARENT, GROUP, 
"c1")))
+                .isInstanceOfSatisfying(BusinessException.class,
+                        ex -> assertThat(ex.getCode()).isEqualTo(502));
+    }
+
+    @Test
+    void getSessionShouldKeepZeroConsumedWhenNoOffsetIsCommittedTest() throws 
Exception {
+        when(admin.examineBrokerClusterInfo()).thenReturn(cluster(BROKER_A));
+        when(admin.getLiteClientInfo(BROKER_A, PARENT, GROUP, "c1"))
+                .thenReturn(clientInfo(1, System.currentTimeMillis(), 
LiteUtil.toLmqName(PARENT, "bob")));
+        when(admin.getLiteGroupInfo(BROKER_A, GROUP, null, 
1)).thenReturn(lag(0));
+        when(admin.getLiteGroupInfo(BROKER_A, GROUP, "bob", 1))
+                .thenReturn(new GetLiteGroupInfoResponseBody());
+
+        LiteTopicSession session = provider.getSession(
+                RocketMQLiteTopicProvider.encodeSessionId(PARENT, GROUP, 
"c1"));
+
+        assertThat(session.getPendingMessages()).isZero();
+        assertThat(session.getConsumedMessages()).isZero();
+        assertThat(session.getTotalMessages()).isZero();
+    }
+
     @Test
     void getSessionFailsWhenNoBrokerReportsTheClient() throws Exception {
         when(admin.examineBrokerClusterInfo()).thenReturn(cluster(BROKER_A));

Reply via email to