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 c86831cc3 fix(metadata): return empty results for topics without a 
broker route (#3346)
c86831cc3 is described below

commit c86831cc3c61e345cfa8ea869f5bb43f1796045a
Author: 烤化の初雪 <[email protected]>
AuthorDate: Tue Sep 8 15:53:08 2026 +0800

    fix(metadata): return empty results for topics without a broker route 
(#3346)
    
    Co-authored-by: unbridled-41 
<[email protected]>
---
 .../provider/apache/RocketMQMetadataProvider.java  | 19 ++++++++
 .../apache/RocketMQMetadataProviderTest.java       | 56 ++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
index 6d77fc91d..4b93fee68 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
@@ -22,6 +22,7 @@ import org.apache.rocketmq.common.constant.PermName;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
 import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
 import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
 import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
@@ -40,6 +41,7 @@ import 
org.apache.rocketmq.studio.common.domain.enums.ConsumeType;
 import org.apache.rocketmq.studio.common.domain.enums.SubscriptionMode;
 import org.apache.rocketmq.studio.common.domain.enums.TopicPerm;
 import org.apache.rocketmq.studio.common.util.Pagination;
+import org.apache.rocketmq.studio.common.util.MqResponseCodes;
 import org.apache.rocketmq.studio.common.util.SubscriptionFilterModes;
 import org.apache.rocketmq.studio.common.util.SystemGroupFilter;
 import org.apache.rocketmq.studio.common.util.SystemTopicFilter;
@@ -447,6 +449,12 @@ public class RocketMQMetadataProvider implements 
MetadataProvider {
             }
             return routes;
         } catch (Exception e) {
+            if (MqResponseCodes.hasResponseCode(e, 
ResponseCode.TOPIC_NOT_EXIST)) {
+                // A record created in the metadata database without a broker 
route is a
+                // normal "not synced yet" state — surface an empty route 
list, not a 502.
+                log.info("Topic {} has no broker route yet: {}", name, 
e.getMessage());
+                return Collections.emptyList();
+            }
             log.warn("Failed to get routes for topic {}: {}", name, 
e.getMessage());
             throw new BusinessException(502, "Failed to get routes for topic " 
+ name + ": " + e.getMessage());
         }
@@ -574,6 +582,17 @@ public class RocketMQMetadataProvider implements 
MetadataProvider {
                     .pageSize(pageSize)
                     .build();
         } catch (Exception e) {
+            if (MqResponseCodes.hasResponseCode(e, 
ResponseCode.TOPIC_NOT_EXIST)) {
+                // Same as routes: a metadata record without a broker route is 
a normal
+                // "not synced yet" state, so the consumer page comes back 
empty.
+                log.info("Topic {} has no broker route yet: {}", name, 
e.getMessage());
+                return TopicConsumerPageVO.builder()
+                        .items(List.of())
+                        .total(0)
+                        .page(page)
+                        .pageSize(pageSize)
+                        .build();
+            }
             log.warn("Failed to get consumers for topic {}: {}", name, 
e.getMessage());
             throw new BusinessException(502, "Failed to get consumers for 
topic " + name + ": " + e.getMessage());
         }
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
index 4bb63e688..729ca200a 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
@@ -27,6 +27,8 @@ import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
 import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
 import org.apache.rocketmq.remoting.protocol.body.GroupList;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
 import org.apache.rocketmq.remoting.protocol.route.BrokerData;
 import org.apache.rocketmq.remoting.protocol.route.QueueData;
 import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
@@ -411,6 +413,60 @@ class RocketMQMetadataProviderTest {
                 .satisfies(error -> assertThat(((BusinessException) 
error).getCode()).isEqualTo(502));
     }
 
+    @Test
+    void getTopicRoutesShouldReturnEmptyListWhenTopicHasNoBrokerRoute() throws 
Exception {
+        DefaultMQAdminExt admin = 
org.mockito.Mockito.mock(DefaultMQAdminExt.class);
+        // Exception shape captured against a live RocketMQ 5.5.0 name server:
+        // MQClientException(responseCode=17, errorMessage="No topic route 
info in name
+        // server for the topic: <topic>").
+        when(admin.examineTopicRouteInfo("TopicA")).thenThrow(new 
MQClientException(
+                ResponseCode.TOPIC_NOT_EXIST,
+                "No topic route info in name server for the topic: TopicA"));
+
+        assertThat(newLiveProvider(admin).getTopicRoutes(null, 
"TopicA")).isEmpty();
+    }
+
+    @Test
+    void getTopicRoutesGradesByResponseCodeOnly() throws Exception {
+        DefaultMQAdminExt admin = 
org.mockito.Mockito.mock(DefaultMQAdminExt.class);
+        // A failure carrying route-absent-looking text but a different 
response code is
+        // a real error and must surface, proving grading no longer keys on 
the message.
+        when(admin.examineTopicRouteInfo("TopicA")).thenThrow(new 
MQClientException(
+                ResponseCode.SYSTEM_ERROR,
+                "No topic route info in name server for the topic: TopicA"));
+
+        assertThatThrownBy(() -> newLiveProvider(admin).getTopicRoutes(null, 
"TopicA"))
+                .isInstanceOf(BusinessException.class)
+                .satisfies(error -> assertThat(((BusinessException) 
error).getCode()).isEqualTo(502));
+    }
+
+    @Test
+    void getTopicConsumersShouldReturnEmptyPageWhenTopicHasNoBrokerRoute() 
throws Exception {
+        DefaultMQAdminExt admin = 
org.mockito.Mockito.mock(DefaultMQAdminExt.class);
+        when(admin.queryTopicConsumeByWho("TopicA")).thenThrow(new 
MQClientException(
+                ResponseCode.TOPIC_NOT_EXIST,
+                "No topic route info in name server for the topic: TopicA"));
+
+        TopicConsumerPageVO page = 
newLiveProvider(admin).getTopicConsumersPage(null, "TopicA", 1, 20);
+
+        assertThat(page.getItems()).isEmpty();
+        assertThat(page.getTotal()).isZero();
+        assertThat(page.getPage()).isEqualTo(1);
+        assertThat(page.getPageSize()).isEqualTo(20);
+    }
+
+    @Test
+    void getTopicConsumersGradesByResponseCodeOnly() throws Exception {
+        DefaultMQAdminExt admin = 
org.mockito.Mockito.mock(DefaultMQAdminExt.class);
+        when(admin.queryTopicConsumeByWho("TopicA")).thenThrow(new 
MQClientException(
+                ResponseCode.SYSTEM_ERROR,
+                "No topic route info in name server for the topic: TopicA"));
+
+        assertThatThrownBy(() -> 
newLiveProvider(admin).getTopicConsumersPage(null, "TopicA", 1, 20))
+                .isInstanceOf(BusinessException.class)
+                .satisfies(error -> assertThat(((BusinessException) 
error).getCode()).isEqualTo(502));
+    }
+
     @Test
     void getTopicConsumersSurfacesAdminFailure() throws Exception {
         DefaultMQAdminExt admin = 
org.mockito.Mockito.mock(DefaultMQAdminExt.class);

Reply via email to