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 f81e73a49 fix(cluster): dedupe name-server rows in views (#5774)
f81e73a49 is described below

commit f81e73a49a7ab776fbc8d71e0d0f05956fc276cc
Author: 0 <[email protected]>
AuthorDate: Mon Oct 19 18:40:06 2026 +0800

    fix(cluster): dedupe name-server rows in views (#5774)
    
    Verified against `rocketmq-studio` at b88aedc34 before merging: 
缺陷仍在(`cluster/broker/RealClusterProvider.java:150-153` 仍只 trim+filter 无 
`distinct`;`RocketMQClusterProvider.buildNameServerList:431-448` 仍无去重,被 `:125`
    
    merge-tree clean against the current trunk. Merged as-is (squash) per the 
maintainer review of 2026-10-19.
    
    Follow-up (non-blocking): the new test hand-rolls a factory instead of 
reusing the `newProvider` helper.
---
 .../studio/cluster/broker/RealClusterProvider.java  |  3 +++
 .../provider/apache/RocketMQClusterProvider.java    |  6 +++++-
 .../cluster/broker/RealClusterProviderTest.java     | 12 ++++++++++++
 .../apache/RocketMQClusterProviderTest.java         | 21 +++++++++++++++++++++
 4 files changed, 41 insertions(+), 1 deletion(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProvider.java
index be27a4d86..b2942c859 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProvider.java
@@ -150,6 +150,9 @@ public class RealClusterProvider implements ClusterProvider 
{
         List<NameServerVO> nameServers = 
Arrays.stream(namesrvAddr.split("[;,]"))
                 .map(String::trim)
                 .filter(addr -> !addr.isEmpty())
+                // The admin client deduplicates the endpoint before 
connecting; the reported
+                // rows must match that view instead of repeating a node per 
repeated segment.
+                .distinct()
                 .map(addr -> 
NameServerVO.builder().addr(addr).status(ClusterStatus.healthy).build())
                 .toList();
 
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
index 3eb1df2ee..ca6070929 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
@@ -42,6 +42,7 @@ import lombok.extern.slf4j.Slf4j;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -435,9 +436,12 @@ public class RocketMQClusterProvider implements 
ClusterProvider {
         }
 
         String[] addrs = namesrvAddr.split("[;,]");
+        Set<String> seen = new LinkedHashSet<>();
         for (String addr : addrs) {
             String trimmed = addr.trim();
-            if (!trimmed.isEmpty()) {
+            if (!trimmed.isEmpty() && seen.add(trimmed)) {
+                // Deduplicate: the admin connection treats a repeated segment 
as one node, so
+                // the reported rows must not repeat it either.
                 nameServers.add(NameServerVO.builder()
                         .addr(trimmed)
                         .status(ClusterStatus.healthy)
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProviderTest.java
index 82b5a7d75..2b2a9d2b0 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RealClusterProviderTest.java
@@ -109,6 +109,18 @@ class RealClusterProviderTest {
         
assertThat(cluster.getBrokers().get(0).getStatus()).isEqualTo(BrokerStatus.running);
     }
 
+    @Test
+    void describeClusterShouldDeduplicateRepeatedNameServerSegments() throws 
Exception {
+        stubClusterInfo("10.0.0.1:9876;10.0.0.2:9876;10.0.0.1:9876", 
sampleClusterInfo());
+
+        ClusterVO cluster = 
provider.describeCluster("10.0.0.1:9876;10.0.0.2:9876;10.0.0.1:9876");
+
+        // The admin client deduplicates the endpoint segments before 
connecting; the reported
+        // name-server rows must not repeat a node the connection itself 
treats once.
+        assertThat(cluster.getNameServers()).extracting("addr")
+                .containsExactly("10.0.0.1:9876", "10.0.0.2:9876");
+    }
+
     @Test
     void describeClusterShouldDefaultAbsentRuntimeCollectionsToEmpty() throws 
Exception {
         stubClusterInfo("10.0.0.1:9876", sampleClusterInfo());
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProviderTest.java
index 58acf901a..aeb7270f9 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProviderTest.java
@@ -29,6 +29,7 @@ import org.apache.rocketmq.studio.cluster.broker.ClusterVO;
 import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
 import org.apache.rocketmq.studio.cluster.broker.MqAdminProperties;
 import org.apache.rocketmq.studio.cluster.broker.RuntimeAdminClientResolver;
+import org.apache.rocketmq.studio.cluster.nameserver.NameServerVO;
 import org.apache.rocketmq.studio.common.domain.enums.ClusterStatus;
 import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
 import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
@@ -62,6 +63,26 @@ import static org.mockito.Mockito.when;
 
 class RocketMQClusterProviderTest {
 
+    @Test
+    void discoverClustersShouldDeduplicateRepeatedNameServerSegments() throws 
Exception {
+        DefaultMQAdminExt adminExt = mock(DefaultMQAdminExt.class);
+        RocketMQProperties properties = new RocketMQProperties();
+        properties.setNamesrvAddr("10.0.0.1:9876;10.0.0.2:9876;10.0.0.1:9876");
+        MqAdminExtFactory adminFactory = mock(MqAdminExtFactory.class);
+        when(adminFactory.execute(anyString(), any(), 
any())).thenAnswer(invocation ->
+                
invocation.<MqAdminExtFactory.AdminAction<Object>>getArgument(2).apply(adminExt));
+        RocketMQClusterProvider provider =
+                new RocketMQClusterProvider(adminFactory, properties, 
mock(RuntimeAdminClientResolver.class));
+
+        when(adminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo());
+
+        List<ClusterVO> clusters = provider.discoverClusters();
+
+        // The admin connection deduplicates the endpoint before use; the 
reported rows must too.
+        
assertThat(clusters.get(0).getNameServers()).extracting(NameServerVO::getAddr)
+                .containsExactly("10.0.0.1:9876", "10.0.0.2:9876");
+    }
+
     @Test
     void discoverClustersShouldParseRuntimeTpsWithExtraWhitespace() throws 
Exception {
         DefaultMQAdminExt adminExt = mock(DefaultMQAdminExt.class);

Reply via email to