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);