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 d2c7de203 fix(client): treat offline group connections as empty
results (#4002)
d2c7de203 is described below
commit d2c7de203dce188ae319b7953c5b3f10c452ac70
Author: 烤化の初雪 <[email protected]>
AuthorDate: Mon Sep 7 17:35:48 2026 +0800
fix(client): treat offline group connections as empty results (#4002)
examineConsumerConnectionInfo answers MQClientException(206, "Not found
the consumer group connection") for any group that is simply offline, so
an all-offline cluster tripped the all-failed guard and GET /api/clients
returned 502 while discarding the producer connections already collected
in the same scan. The explicit producer-group lookup failed the same way
for offline groups.
Classify the offline-group answers as a normal empty outcome: count them
as successful per-group results in the consumer scan and return an empty
list for the explicit producer-group query. Genuine broker failures and
partial scans keep their existing behavior.
Co-authored-by: unbridled-41
<[email protected]>
---
.../provider/apache/RocketMQClientProvider.java | 25 +++++++++++--
.../apache/RocketMQClientProviderTest.java | 43 ++++++++++++++++++++++
2 files changed, 65 insertions(+), 3 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 237e4dce6..63b7cdcc5 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
@@ -36,6 +36,7 @@ import
org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.common.domain.enums.ClientLanguage;
import org.apache.rocketmq.studio.common.domain.enums.ClientType;
import org.apache.rocketmq.studio.common.domain.enums.Protocol;
+import org.apache.rocketmq.studio.common.util.MqResponseCodes;
import org.apache.rocketmq.studio.common.util.SystemGroupFilter;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import lombok.RequiredArgsConstructor;
@@ -171,9 +172,10 @@ public class RocketMQClientProvider implements
ClientProvider {
connection, ClientType.Producer, topic,
producerGroup, null))
.toList();
} catch (MQClientException e) {
- if (isTopicNotExist(e)) {
- // A non-existent topic is a normal "nothing here" outcome —
the client
- // page should show an empty list, not a 502 that looks like a
failure.
+ if (isTopicNotExist(e) || isGroupConnectionAbsent(e)) {
+ // A missing topic route or an offline producer group are
normal "nothing
+ // here" outcomes — the client page should show an empty list,
not a 502
+ // that looks like a failure.
return List.of();
}
throw new BusinessException(502,
@@ -184,6 +186,17 @@ public class RocketMQClientProvider implements
ClientProvider {
}
}
+ private boolean isGroupConnectionAbsent(MQClientException e) {
+ if (MqResponseCodes.hasResponseCode(e,
ResponseCode.CONSUMER_NOT_ONLINE)) {
+ // rocketmq-tools examineConsumerConnectionInfo throws
CONSUMER_NOT_ONLINE (206)
+ // for a group with no online connections.
+ return true;
+ }
+ String message = e.getErrorMessage() == null ? e.getMessage() :
e.getErrorMessage();
+ return message != null && (message.contains("Not found the consumer
group connection")
+ || message.contains("Not found the producer group
connection"));
+ }
+
private boolean isTopicNotExist(MQClientException e) {
if (e.getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) {
return true;
@@ -324,6 +337,12 @@ public class RocketMQClientProvider implements
ClientProvider {
groupEntry.getValue()));
}
} catch (Exception e) {
+ if (e instanceof MQClientException clientException &&
isGroupConnectionAbsent(clientException)) {
+ // An offline group is a normal "no connections right now"
answer, not a
+ // broken scan — count it so an all-offline cluster stays
an empty result.
+ successfulGroupQueries++;
+ continue;
+ }
log.warn("Failed to examine consumer connection for group={},
skipping", group, e);
}
}
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 f23be04ca..a732b6ebd 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
@@ -504,6 +504,49 @@ class RocketMQClientProviderTest {
});
}
+ @Test
+ void consumerScanTreatsOfflineGroupsAsEmptyInsteadOf502() throws Exception
{
+ SubscriptionGroupWrapper wrapper = subscriptionGroups("group-a",
"group-b");
+
when(adminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo("127.0.0.1:10911"));
+ when(adminExt.getAllSubscriptionGroup("127.0.0.1:10911",
5000L)).thenReturn(wrapper);
+
when(adminExt.examineConsumerConnectionInfo(anyString())).thenThrow(new
MQClientException(
+ 206, "Not found the consumer group connection"));
+
+ List<ClientConnectionVO> connections =
provider.findConnections("instance-a", "cluster-a", null);
+
+ assertThat(connections).isEmpty();
+ }
+
+ @Test
+ void consumerScanReturnsOfflineGroupResultsWhenAnotherGroupFails() throws
Exception {
+ SubscriptionGroupWrapper wrapper = subscriptionGroups("group-a",
"group-b");
+ ConsumerConnection consumerConnection = new ConsumerConnection();
+ consumerConnection.setConnectionSet(new
HashSet<>(List.of(connection("consumer-client", "10.0.0.2:1000"))));
+
when(adminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo("127.0.0.1:10911"));
+ when(adminExt.getAllSubscriptionGroup("127.0.0.1:10911",
5000L)).thenReturn(wrapper);
+ when(adminExt.examineConsumerConnectionInfo("group-a")).thenThrow(new
MQClientException(
+ 206, "Not found the consumer group connection"));
+
when(adminExt.examineConsumerConnectionInfo("group-b")).thenReturn(consumerConnection);
+
+ List<ClientConnectionVO> connections =
provider.findConnections("instance-a", "cluster-a", "Consumer");
+
+ assertThat(connections).singleElement().satisfies(connection -> {
+ assertThat(connection.getClientId()).isEqualTo("consumer-client");
+ assertThat(connection.getGroupOrTopic()).isEqualTo("group-b");
+ });
+ }
+
+ @Test
+ void producerQueryWithExplicitOfflineGroupReturnsEmptyInsteadOf502()
throws Exception {
+ when(adminExt.examineProducerConnectionInfo("pg-order",
"TopicA")).thenThrow(
+ new MQClientException("Not found the producer group
connection", null));
+
+ List<ClientConnectionVO> connections =
+ provider.findProducerConnections("instance-a", "TopicA",
"pg-order");
+
+ assertThat(connections).isEmpty();
+ }
+
private static SubscriptionGroupWrapper subscriptionGroups(String...
names) {
SubscriptionGroupWrapper wrapper = new SubscriptionGroupWrapper();
ConcurrentHashMap<String, SubscriptionGroupConfig> groups = new
ConcurrentHashMap<>();