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 c818121d fix(cluster): report real cluster names in client connections 
(#1699)
c818121d is described below

commit c818121da4cf485aac540f4f588f3649d621b7cd
Author: aias00 <[email protected]>
AuthorDate: Tue Aug 11 20:50:41 2026 +0800

    fix(cluster): report real cluster names in client connections (#1699)
---
 .../provider/apache/RocketMQClientProvider.java    | 75 +++++++++++-----------
 .../apache/RocketMQClientProviderTest.java         | 62 +++++++++++++++++-
 2 files changed, 96 insertions(+), 41 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
index abe5f98a..2c259dfd 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
@@ -43,12 +43,10 @@ import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 
 /**
  * Live {@link ClientProvider} backed by the RocketMQ admin API. It discovers 
producer
@@ -125,46 +123,49 @@ public class RocketMQClientProvider implements 
ClientProvider {
 
     private List<ClientConnectionVO> findAllProducerConnections(
             MQAdminExt adminExt, String clusterId) {
-        Set<String> brokerAddresses = collectProducerBrokerAddresses(adminExt);
+        BrokerTopology topology = discoverBrokerTopology(adminExt, clusterId, 
"producer connections");
         Map<String, ClientConnectionVO> connections = new LinkedHashMap<>();
         int successfulBrokers = 0;
-        for (String brokerAddress : brokerAddresses) {
+        for (String brokerAddress : topology.brokerAddresses()) {
             try {
                 ProducerTableInfo producerTable = 
adminExt.getAllProducerInfo(brokerAddress);
                 successfulBrokers++;
-                addProducerConnections(connections, producerTable, clusterId);
+                addProducerConnections(connections, producerTable, 
topology.clusterFor(brokerAddress));
             } catch (Exception e) {
                 log.warn("Failed to fetch producer connections from broker={}, 
skipping", brokerAddress, e);
             }
         }
-        if (!brokerAddresses.isEmpty() && successfulBrokers == 0) {
+        if (!topology.brokerAddresses().isEmpty() && successfulBrokers == 0) {
             throw new BusinessException(502, "Failed to query producer 
connections from all brokers");
         }
         return new ArrayList<>(connections.values());
     }
 
-    private Set<String> collectProducerBrokerAddresses(MQAdminExt adminExt) {
+    private BrokerTopology discoverBrokerTopology(MQAdminExt adminExt, String 
clusterId, String operation) {
         ClusterInfo clusterInfo;
         try {
             clusterInfo = adminExt.examineBrokerClusterInfo();
         } catch (Exception e) {
             throw new BusinessException(502,
-                    "Failed to discover brokers for producer connections: " + 
rootMessage(e));
+                    "Failed to discover brokers for " + operation + ": " + 
rootMessage(e));
         }
-        Set<String> addresses = new LinkedHashSet<>();
+        Map<String, String> clusterByAddress = new LinkedHashMap<>();
         if (clusterInfo == null || clusterInfo.getBrokerAddrTable() == null) {
-            return addresses;
+            return new BrokerTopology(clusterByAddress);
         }
         for (BrokerData brokerData : 
clusterInfo.getBrokerAddrTable().values()) {
-            if (brokerData == null) {
+            if (brokerData == null || brokerData.getBrokerAddrs() == null
+                    || brokerData.getBrokerAddrs().isEmpty()) {
                 continue;
             }
             String brokerAddress = brokerData.selectBrokerAddr();
-            if (brokerAddress != null && !brokerAddress.isBlank()) {
-                addresses.add(brokerAddress);
+            String brokerCluster = brokerData.getCluster();
+            if (brokerAddress != null && !brokerAddress.isBlank()
+                    && (clusterId == null || clusterId.equals(brokerCluster))) 
{
+                clusterByAddress.putIfAbsent(brokerAddress, brokerCluster);
             }
         }
-        return addresses;
+        return new BrokerTopology(clusterByAddress);
     }
 
     private void addProducerConnections(
@@ -207,9 +208,10 @@ public class RocketMQClientProvider implements 
ClientProvider {
 
     private List<ClientConnectionVO> findConsumerConnections(MQAdminExt 
adminExt, String clusterId) {
         List<ClientConnectionVO> result = new ArrayList<>();
-        Set<String> groups = collectSubscriptionGroups(adminExt);
+        Map<String, String> groups = collectSubscriptionGroups(adminExt, 
clusterId);
         int successfulGroupQueries = 0;
-        for (String group : groups) {
+        for (Map.Entry<String, String> groupEntry : groups.entrySet()) {
+            String group = groupEntry.getKey();
             if (isSystemGroup(group)) {
                 continue;
             }
@@ -223,7 +225,8 @@ public class RocketMQClientProvider implements 
ClientProvider {
                     if (connection == null) {
                         continue;
                     }
-                    result.add(toConnectionVO(connection, ClientType.Consumer, 
group, null, clusterId));
+                    result.add(toConnectionVO(connection, ClientType.Consumer, 
group, null,
+                            groupEntry.getValue()));
                 }
             } catch (Exception e) {
                 log.warn("Failed to examine consumer connection for group={}, 
skipping", group, e);
@@ -235,36 +238,20 @@ public class RocketMQClientProvider implements 
ClientProvider {
         return result;
     }
 
-    private Set<String> collectSubscriptionGroups(MQAdminExt adminExt) {
-        Set<String> groups = new LinkedHashSet<>();
-        ClusterInfo clusterInfo;
-        try {
-            clusterInfo = adminExt.examineBrokerClusterInfo();
-        } catch (Exception e) {
-            log.warn("Failed to fetch cluster info for consumer connection 
scan", e);
-            throw new BusinessException(502, "Failed to discover brokers for 
consumer connections: "
-                    + rootMessage(e));
-        }
-        if (clusterInfo == null || clusterInfo.getBrokerAddrTable() == null) {
-            return groups;
-        }
+    private Map<String, String> collectSubscriptionGroups(MQAdminExt adminExt, 
String clusterId) {
+        Map<String, String> groups = new LinkedHashMap<>();
+        BrokerTopology topology = discoverBrokerTopology(adminExt, clusterId, 
"consumer connections");
         int attemptedBrokerQueries = 0;
         int successfulBrokerQueries = 0;
-        for (BrokerData brokerData : 
clusterInfo.getBrokerAddrTable().values()) {
-            if (brokerData == null) {
-                continue;
-            }
-            String brokerAddr = brokerData.selectBrokerAddr();
-            if (brokerAddr == null) {
-                continue;
-            }
+        for (String brokerAddr : topology.brokerAddresses()) {
             try {
                 attemptedBrokerQueries++;
                 SubscriptionGroupWrapper wrapper =
                         adminExt.getAllSubscriptionGroup(brokerAddr, 
SUBSCRIPTION_GROUP_TIMEOUT_MILLIS);
                 successfulBrokerQueries++;
                 if (wrapper != null && wrapper.getSubscriptionGroupTable() != 
null) {
-                    
groups.addAll(wrapper.getSubscriptionGroupTable().keySet());
+                    wrapper.getSubscriptionGroupTable().keySet().forEach(group 
->
+                            groups.putIfAbsent(group, 
topology.clusterFor(brokerAddr)));
                 }
             } catch (Exception e) {
                 log.warn("Failed to fetch subscription groups from broker={}, 
skipping", brokerAddr, e);
@@ -347,4 +334,14 @@ public class RocketMQClientProvider implements 
ClientProvider {
                 ? current.getClass().getSimpleName()
                 : message;
     }
+
+    private record BrokerTopology(Map<String, String> clusterByAddress) {
+        private List<String> brokerAddresses() {
+            return List.copyOf(clusterByAddress.keySet());
+        }
+
+        private String clusterFor(String brokerAddress) {
+            return clusterByAddress.get(brokerAddress);
+        }
+    }
 }
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProviderTest.java
index ded1bb8a..e71932cd 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProviderTest.java
@@ -53,6 +53,7 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -114,6 +115,32 @@ class RocketMQClientProviderTest {
         verify(adminExt, never()).examineProducerConnectionInfo(anyString(), 
anyString());
     }
 
+    @Test
+    void clientScanUsesActualBrokerClustersAndFiltersRequestedCluster() throws 
Exception {
+        
when(adminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo(Map.of(
+                "127.0.0.1:10911", "cluster-a",
+                "127.0.0.2:10911", "cluster-b")));
+        when(adminExt.getAllProducerInfo("127.0.0.1:10911"))
+                .thenReturn(new ProducerTableInfo(Map.of(
+                        "pg-a", List.of(producerInfo("producer-a", 
"10.0.0.1:1000")))));
+        when(adminExt.getAllProducerInfo("127.0.0.2:10911"))
+                .thenReturn(new ProducerTableInfo(Map.of(
+                        "pg-b", List.of(producerInfo("producer-b", 
"10.0.0.2:1000")))));
+
+        List<ClientConnectionVO> allConnections = 
provider.findConnections("instance-a", null, "Producer");
+        List<ClientConnectionVO> clusterBConnections = 
provider.findConnections("instance-a", "cluster-b", "Producer");
+
+        assertThat(allConnections)
+                .extracting(ClientConnectionVO::getClusterName)
+                .containsExactlyInAnyOrder("cluster-a", "cluster-b");
+        assertThat(clusterBConnections).singleElement().satisfies(connection 
-> {
+            assertThat(connection.getClientId()).isEqualTo("producer-b");
+            assertThat(connection.getClusterName()).isEqualTo("cluster-b");
+        });
+        verify(adminExt).getAllProducerInfo("127.0.0.1:10911");
+        verify(adminExt, times(2)).getAllProducerInfo("127.0.0.2:10911");
+    }
+
     @Test
     void producerScanReturnsPartialResultsWhenOneBrokerFails() throws 
Exception {
         when(adminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo(
@@ -220,6 +247,27 @@ class RocketMQClientProviderTest {
         verify(adminExt).getAllSubscriptionGroup("127.0.0.1:10911", 5000L);
     }
 
+    @Test
+    void 
consumerScanFiltersSubscriptionGroupsByClusterAndPreservesClusterName() throws 
Exception {
+        
when(adminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo(Map.of(
+                "127.0.0.1:10911", "cluster-a",
+                "127.0.0.2:10911", "cluster-b")));
+        when(adminExt.getAllSubscriptionGroup("127.0.0.2:10911", 5000L))
+                .thenReturn(subscriptionGroups("group-b"));
+        ConsumerConnection consumerConnection = new ConsumerConnection();
+        consumerConnection.setConnectionSet(new 
HashSet<>(List.of(connection("consumer-b", "10.0.0.2:1000"))));
+        
when(adminExt.examineConsumerConnectionInfo("group-b")).thenReturn(consumerConnection);
+
+        List<ClientConnectionVO> connections = 
provider.findConnections("instance-a", "cluster-b", "Consumer");
+
+        assertThat(connections).singleElement().satisfies(connection -> {
+            assertThat(connection.getClientId()).isEqualTo("consumer-b");
+            assertThat(connection.getClusterName()).isEqualTo("cluster-b");
+        });
+        verify(adminExt, never()).getAllSubscriptionGroup("127.0.0.1:10911", 
5000L);
+        verify(adminExt).getAllSubscriptionGroup("127.0.0.2:10911", 5000L);
+    }
+
     @Test
     void consumerScanFailsWhenBrokerDiscoveryFails() throws Exception {
         when(adminExt.examineBrokerClusterInfo()).thenThrow(new 
IllegalStateException("broker unavailable"));
@@ -324,12 +372,22 @@ class RocketMQClientProviderTest {
     }
 
     private static ClusterInfo clusterInfo(String... brokerAddresses) {
+        Map<String, String> clusters = new HashMap<>();
+        for (int i = 0; i < brokerAddresses.length; i++) {
+            clusters.put(brokerAddresses[i], "cluster-a");
+        }
+        return clusterInfo(clusters);
+    }
+
+    private static ClusterInfo clusterInfo(Map<String, String> 
clustersByAddress) {
         ClusterInfo clusterInfo = new ClusterInfo();
         Map<String, BrokerData> brokerAddrTable = new HashMap<>();
-        for (int i = 0; i < brokerAddresses.length; i++) {
+        int i = 0;
+        for (Map.Entry<String, String> entry : clustersByAddress.entrySet()) {
             String brokerName = "broker-" + i;
             brokerAddrTable.put(brokerName, new BrokerData(
-                    "cluster-a", brokerName, new HashMap<>(Map.of(0L, 
brokerAddresses[i]))));
+                    entry.getValue(), brokerName, new HashMap<>(Map.of(0L, 
entry.getKey()))));
+            i++;
         }
         clusterInfo.setBrokerAddrTable(brokerAddrTable);
         return clusterInfo;

Reply via email to