You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by li...@apache.org on 2026/08/10 16:28:21 UTC

(rocketmq-dashboard) branch rocketmq-studio updated: fix(topic): persist type/remark, scope operations to target cluster, reset-offset validation (#1399, #1429, #1442)

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 24715633 fix(topic): persist type/remark, scope operations to target cluster, reset-offset validation (#1399, #1429, #1442)
24715633 is described below

commit 24715633108a0c592fc80ca23311c371c263e3f8
Author: Yu Xinqiang <yu...@tju.edu.cn>
AuthorDate: Tue Aug 11 00:28:16 2026 +0800

    fix(topic): persist type/remark, scope operations to target cluster, reset-offset validation (#1399, #1429, #1442)
    
    * [ISSUE #1392] Persist topicType and remark in updateTopic, remove dead variable
    
    - updateTopic now persists topicType and remark to the database,
      matching the behavior of createTopic
    - Removed dead fullTopic variable in sendMessage that was computed
      but never used
    
    Fixes #1392
    
    * [ISSUE #1428] Scope topic/group operations to target cluster brokers
    
    getAllMasterBrokerAddrs returned all brokers across all clusters,
    causing topics and groups to be created on brokers outside the
    target cluster. This fix:
    
    - Adds getMasterBrokerAddrsForCluster that filters by cluster name
      using clusterAddrTable
    - Updates createTopic, updateTopic, createConsumerGroup to use the
      cluster-scoped method
    - Falls back to all brokers when cluster name is unknown
    
    Fixes #1428
    
    * [ISSUE #1441] Validate topic field in reset offset
    
    The reset offset endpoint accepted null/blank topic without validation,
    causing a 500 error instead of a clear 400. This fix adds @NotBlank to
    the DTO and runtime validation in the admin client.
    
    Fixes #1441
---
 .../instance/group/ResetConsumerOffsetDTO.java     |  1 +
 .../provider/apache/RocketMQAdminClientImpl.java   | 52 ++++++++++++++++++++--
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/group/ResetConsumerOffsetDTO.java b/server/src/main/java/org/apache/rocketmq/studio/instance/group/ResetConsumerOffsetDTO.java
index 80ea5f75..3cc3c318 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/group/ResetConsumerOffsetDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/group/ResetConsumerOffsetDTO.java
@@ -39,5 +39,6 @@ public class ResetConsumerOffsetDTO {
     @Positive(message = "timestamp must be positive")
     private Long timestamp;
 
+    @NotBlank(message = "topic is required")
     private String topic;
 }
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java
index ec80dfda..c09b5b4c 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java
@@ -149,7 +149,7 @@ public class RocketMQAdminClientImpl implements AdminClient {
                 TopicPerm effectivePerm = topic.getPerm() != null
                         ? topic.getPerm()
                         : existing == null ? TopicPerm.RW : fromRocketMQPerm(existing.getPerm());
-                Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+                Set<String> brokerAddrs = getMasterBrokerAddrsForCluster(admin, clusterName);
                 if (brokerAddrs.isEmpty()) {
                     throw new BusinessException(500, "No broker available to create topic");
                 }
@@ -230,7 +230,7 @@ public class RocketMQAdminClientImpl implements AdminClient {
                 TopicPerm effectivePerm = topic.getPerm() != null
                         ? topic.getPerm()
                         : existing == null ? TopicPerm.RW : fromRocketMQPerm(existing.getPerm());
-                Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+                Set<String> brokerAddrs = getMasterBrokerAddrsForCluster(admin, clusterName);
                 if (brokerAddrs.isEmpty()) {
                     throw new BusinessException(500, "No broker available to update topic");
                 }
@@ -250,6 +250,12 @@ public class RocketMQAdminClientImpl implements AdminClient {
                     existing.setWriteQueueNums(writeQueues);
                     existing.setReadQueueNums(readQueues);
                     existing.setPerm(topicConfig.getPerm());
+                    if (topic.getType() != null) {
+                        existing.setTopicType(topic.getType().name());
+                    }
+                    if (StringUtils.hasText(topic.getRemark())) {
+                        existing.setRemark(topic.getRemark());
+                    }
                     existing.setUpdatedAt(LocalDateTime.now());
                     topicMapper.updateById(existing);
                 }
@@ -384,7 +390,8 @@ public class RocketMQAdminClientImpl implements AdminClient {
         String groupName = group.getName();
 
         try {
-            Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+            String groupClusterName = getClusterName(admin);
+            Set<String> brokerAddrs = getMasterBrokerAddrsForCluster(admin, groupClusterName);
             if (brokerAddrs.isEmpty()) {
                 throw new BusinessException(500, "No broker available to create consumer group");
             }
@@ -402,7 +409,6 @@ public class RocketMQAdminClientImpl implements AdminClient {
 
             // Persist to DB, upserting so re-creating an existing group does not violate the
             // unique (cluster_id, name) key.
-            String groupClusterName = getClusterName(admin);
             RmqGroup entity = groupMapper.selectOne(new LambdaQueryWrapper<RmqGroup>()
                     .eq(RmqGroup::getClusterId, groupClusterName)
                     .eq(RmqGroup::getName, groupName));
@@ -481,6 +487,9 @@ public class RocketMQAdminClientImpl implements AdminClient {
 
     @Override
     public void resetOffset(String instanceId, String name, long timestamp, String topic) {
+        if (!StringUtils.hasText(topic)) {
+            throw new BusinessException(400, "topic is required for offset reset");
+        }
         try {
             if (StringUtils.hasText(instanceId)) {
                 runtimeAdminClientResolver.execute(instanceId, admin -> {
@@ -560,6 +569,41 @@ public class RocketMQAdminClientImpl implements AdminClient {
         return addrs;
     }
 
+    /**
+     * Returns master broker addresses for the specified cluster only, using the
+     * clusterAddrTable to map cluster name to broker names. Falls back to all
+     * brokers when the cluster name is unknown or the cluster table is missing.
+     */
+    private Set<String> getMasterBrokerAddrsForCluster(MQAdminExt admin, String clusterName) throws Exception {
+        if (!StringUtils.hasText(clusterName)) {
+            return getAllMasterBrokerAddrs(admin);
+        }
+        ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();
+        if (clusterInfo == null || clusterInfo.getClusterAddrTable() == null
+                || clusterInfo.getBrokerAddrTable() == null) {
+            return getAllMasterBrokerAddrs(admin);
+        }
+        Set<String> brokerNames = clusterInfo.getClusterAddrTable().get(clusterName);
+        if (brokerNames == null || brokerNames.isEmpty()) {
+            return getAllMasterBrokerAddrs(admin);
+        }
+        Set<String> addrs = new HashSet<>();
+        for (String brokerName : brokerNames) {
+            BrokerData brokerData = clusterInfo.getBrokerAddrTable().get(brokerName);
+            if (brokerData == null || brokerData.getBrokerAddrs() == null) {
+                continue;
+            }
+            String masterAddr = brokerData.getBrokerAddrs().get(0L);
+            if (masterAddr == null && !brokerData.getBrokerAddrs().isEmpty()) {
+                masterAddr = brokerData.getBrokerAddrs().values().iterator().next();
+            }
+            if (masterAddr != null) {
+                addrs.add(masterAddr);
+            }
+        }
+        return addrs.isEmpty() ? getAllMasterBrokerAddrs(admin) : addrs;
+    }
+
     private String getClusterName(MQAdminExt admin) {
         try {
             ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();