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 4867a7de1 fix(alert): stop offering the cloud queue maximum no cloud 
collector measures (#6527)
4867a7de1 is described below

commit 4867a7de1d6c0ebb1f9537af045697c9ac4354ce
Author: Apulupie <[email protected]>
AuthorDate: Thu Oct 15 18:14:18 2026 +0800

    fix(alert): stop offering the cloud queue maximum no cloud collector 
measures (#6527)
    
    #6184 made CloudRocketMqBusinessMetricsCollector publish 
consumer.lag.max_queue as
    UNSUPPORTED only, because the Aliyun and Tencent progress rows are 
per-topic aggregates
    without queue offsets - but the capability catalog still listed the metric 
for cloud instances,
    so the rule editor offered it and validate() accepted it. 
AlertRuleEvaluator reports an
    UNSUPPORTED sample as matched with the condition unmet, so such a rule 
could never fire.
    
    Drop the metric from BUSINESS_CLOUD, which is what the catalog serves for a 
cloud instance, and
    correct the design doc's source column for the metric; an Apache instance 
keeps the metric - its
    collector derives the maximum from real per-queue offsets - and the other 
cloud metrics are
    untouched. Existing stored rules are not migrated (the follow-up note in 
#6184 leaves that
    decision open).
---
 docs/studio-native-alerting-design.md              |  2 +-
 .../ops/alert/NativeAlertMetricCatalogService.java |  4 ++-
 .../alert/NativeAlertMetricCatalogServiceTest.java | 32 +++++++++++++++++++++-
 3 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/docs/studio-native-alerting-design.md 
b/docs/studio-native-alerting-design.md
index e3242fa8d..542a7ad37 100644
--- a/docs/studio-native-alerting-design.md
+++ b/docs/studio-native-alerting-design.md
@@ -139,7 +139,7 @@ record MetricSample(
 | Cluster | `proxy.availability` | Proxy | TCP probe of the gRPC listener 
discovered for the selected instance |
 | Cluster | `cloud.instance.availability` | Managed cloud instance | 
Aliyun/Tencent control-plane instance status |
 | Business | `consumer.lag.total` | Consumer Group / Topic | Consumer progress 
(Apache, Aliyun, Tencent) |
-| Business | `consumer.lag.max_queue` | Consumer Group / Queue | Consumer 
progress (Apache, Aliyun, Tencent) |
+| Business | `consumer.lag.max_queue` | Consumer Group / Queue | Apache 
consumer progress only: the Aliyun and Tencent progress rows are per-topic 
aggregates without queue offsets, so the cloud collector publishes this metric 
as unsupported |
 | Business | `consumer.delay.seconds` | Consumer Group | Apache broker consume 
stats; emitted only when a consumption timestamp is available |
 | Business | `topic.backlog.total` | Topic / Consumer Group | Topic and 
consumer offsets; each sample is scoped to one Topic and consumer group to 
avoid cross-group double counting |
 | Business | `dlq.message.count` | Consumer Group / DLQ | DLQ provider |
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogService.java
 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogService.java
index 3eed1b8cc..e05df19f0 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogService.java
@@ -38,9 +38,11 @@ public class NativeAlertMetricCatalogService {
             new NativeAlertMetricInfo("consumer.delay.seconds", "Consumer 
delay", "seconds", true),
             new NativeAlertMetricInfo("topic.backlog.total", "Topic backlog 
(per consumer group)", "messages", true),
             new NativeAlertMetricInfo("dlq.message.count", "DLQ message 
count", "messages", true));
+    // No cloud queue maximum: the Aliyun and Tencent progress rows are 
per-topic aggregates without
+    // queue offsets, so CloudRocketMqBusinessMetricsCollector publishes 
consumer.lag.max_queue as
+    // UNSUPPORTED only (#6184) - a rule the operator could pick here would 
never fire.
     private static final List<NativeAlertMetricInfo> BUSINESS_CLOUD = List.of(
             new NativeAlertMetricInfo("consumer.lag.total", "Consumer lag 
total", "messages", true),
-            new NativeAlertMetricInfo("consumer.lag.max_queue", "Consumer lag 
max queue", "messages", true),
             new NativeAlertMetricInfo("topic.backlog.total", "Topic backlog 
(per consumer group)", "messages", true));
     private static final List<NativeAlertMetricInfo> CLUSTER_CLOUD = List.of(
             new NativeAlertMetricInfo("cloud.instance.availability", "Cloud 
instance availability", "", false));
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogServiceTest.java
index b94bbd334..63723b0c2 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/NativeAlertMetricCatalogServiceTest.java
@@ -7,6 +7,7 @@
 package org.apache.rocketmq.studio.ops.alert;
 
 import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
 import org.apache.rocketmq.studio.instance.InstanceRepository;
 import org.apache.rocketmq.studio.instance.InstanceVO;
 import org.junit.jupiter.api.Test;
@@ -34,7 +35,7 @@ class NativeAlertMetricCatalogServiceTest {
         assertThat(service.list("apache", 
AlertDomain.CLUSTER)).extracting(NativeAlertMetricInfo::key)
                 .contains("broker.jvm.heap.usage_ratio", 
"broker.send_queue.usage_ratio", "proxy.availability");
         assertThat(service.list("aliyun", 
AlertDomain.BUSINESS)).extracting(NativeAlertMetricInfo::key)
-                .containsExactly("consumer.lag.total", 
"consumer.lag.max_queue", "topic.backlog.total");
+                .containsExactly("consumer.lag.total", "topic.backlog.total");
         assertThat(service.list("aliyun", 
AlertDomain.CLUSTER)).extracting(NativeAlertMetricInfo::key)
                 .containsExactly("cloud.instance.availability");
         assertThatThrownBy(() -> 
service.validate(AlertRuleVO.builder().domain(AlertDomain.CLUSTER)
@@ -42,6 +43,35 @@ class NativeAlertMetricCatalogServiceTest {
                 .hasMessageContaining("not supported");
     }
 
+    @Test
+    void doesNotOfferTheCloudQueueMaximumNoCloudCollectorMeasuresTest() {
+        InstanceRepository repository = mock(InstanceRepository.class);
+        
when(repository.findByIdentifier("aliyun")).thenReturn(Optional.of(InstanceVO.builder()
+                .name("aliyun").vendor(InstanceVendor.ALIYUN).build()));
+        
when(repository.findByIdentifier("tencent")).thenReturn(Optional.of(InstanceVO.builder()
+                .name("tencent").vendor(InstanceVendor.TENCENT).build()));
+        
when(repository.findByIdentifier("apache")).thenReturn(Optional.of(InstanceVO.builder()
+                .name("apache").vendor(InstanceVendor.APACHE).build()));
+        NativeAlertMetricCatalogService service = new 
NativeAlertMetricCatalogService(repository);
+
+        // The cloud progress rows are per-topic aggregates without queue 
offsets, so the cloud
+        // collector can only publish a queue maximum as unsupported: offering 
it here lets an
+        // operator save a cloud rule that can never fire.
+        assertThat(service.list("aliyun", 
AlertDomain.BUSINESS)).extracting(NativeAlertMetricInfo::key)
+                .containsExactly("consumer.lag.total", "topic.backlog.total");
+        assertThat(service.list("tencent", 
AlertDomain.BUSINESS)).extracting(NativeAlertMetricInfo::key)
+                .containsExactly("consumer.lag.total", "topic.backlog.total");
+        assertThatThrownBy(() -> 
service.validate(AlertRuleVO.builder().domain(AlertDomain.BUSINESS)
+                
.instanceId("aliyun").metric("consumer.lag.max_queue").build()))
+                .isInstanceOf(BusinessException.class)
+                .hasMessageContaining("not supported");
+        // The Apache collector derives the queue maximum from real per-queue 
offsets: unchanged.
+        assertThat(service.list("apache", 
AlertDomain.BUSINESS)).extracting(NativeAlertMetricInfo::key)
+                .contains("consumer.lag.max_queue");
+        service.validate(AlertRuleVO.builder().domain(AlertDomain.BUSINESS)
+                
.instanceId("apache").metric("consumer.lag.max_queue").build());
+    }
+
     @Test
     void normalizesMetricKeysBeforeNativeAndCustomValidationTest() {
         InstanceRepository repository = mock(InstanceRepository.class);

Reply via email to