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 fb6455a03 fix(consumer): keep an unknown total lag from being a 
partial subtotal (#7053)
fb6455a03 is described below

commit fb6455a0352e7431144eb355ea66f1000b7fbc55
Author: 0 <[email protected]>
AuthorDate: Wed Oct 28 01:08:47 2026 +0800

    fix(consumer): keep an unknown total lag from being a partial subtotal 
(#7053)
    
    When the queue scan did not cover every queue, analyzeConsumerGroupHealth 
fell back
    to the sum of the queues it did see and reported that subtotal as the 
group's total
    lag - a partial measurement presented as a complete one. reportedLag now 
yields null
    unless every queue in the progress list had a readable lag, and the single 
render
    site already treats null as unknown. The health-issue path keeps using the 
known
    subtotal (summaryReportedLag ?? totalKnownLag), so this changes only what is
    reported as the total, not which issues are raised.
    
    This complements rather than duplicates the delay-availability work that 
landed in
    #5918: that change covers delaySeconds, which has no sentinel and needs a 
boolean
    flag, while totalLag already carries the -1 sentinel, so a single 
isLagAvailable
    conversion at the boundary is enough. The test file conflicted with those 
additions;
    both sides' cases are kept.
---
 web/src/utils/consumerGroupDiagnostics.test.ts | 70 +++++++++++++++++++++++++-
 web/src/utils/consumerGroupDiagnostics.ts      |  7 +--
 2 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/web/src/utils/consumerGroupDiagnostics.test.ts 
b/web/src/utils/consumerGroupDiagnostics.test.ts
index 19f6cce89..02402de34 100644
--- a/web/src/utils/consumerGroupDiagnostics.test.ts
+++ b/web/src/utils/consumerGroupDiagnostics.test.ts
@@ -173,7 +173,7 @@ describe('consumer group diagnostics', () => {
 
     expect(diagnostics.status).toBe('warning');
     expect(diagnostics.summary).toMatchObject({
-      reportedLag: 0,
+      reportedLag: null,
       unknownQueueCount: 1,
       maxQueueLag: null,
       maxHeartbeatAgeSeconds: 660,
@@ -213,4 +213,72 @@ describe('consumer group diagnostics', () => {
     expect(diagnostics.issues.map((item) => 
item.code)).toContain('HIGH_CONSUME_DELAY');
     expect(diagnostics.issues.map((item) => 
item.code)).not.toContain('CONSUME_DELAY_UNKNOWN');
   });
+
+  it('keeps the reported lag unknown when only some queue lags are available', 
() => {
+    const diagnostics = analyzeConsumerGroupHealth(
+      group({ totalLag: -1 }),
+      [subscription()],
+      [queue({ diffTotal: 17 }), queue({ broker: 'broker-b', queueId: 1, 
diffTotal: -1 })],
+      { now: '2026-08-31T12:01:00Z' },
+    );
+
+    expect(diagnostics.summary).toMatchObject({
+      totalKnownLag: 17,
+      reportedLag: null,
+      unknownQueueCount: 1,
+    });
+  });
+
+  it('falls back to the queue subtotal only when every queue lag is 
available', () => {
+    const diagnostics = analyzeConsumerGroupHealth(
+      group({ totalLag: -1 }),
+      [subscription()],
+      [queue({ diffTotal: 10 }), queue({ broker: 'broker-b', queueId: 1, 
diffTotal: 7 })],
+      { now: '2026-08-31T12:01:00Z' },
+    );
+
+    expect(diagnostics.summary).toMatchObject({
+      totalKnownLag: 17,
+      reportedLag: 17,
+      unknownQueueCount: 0,
+    });
+  });
+
+  it('preserves an independently measured zero total lag', () => {
+    const diagnostics = analyzeConsumerGroupHealth(
+      group({ totalLag: 0 }),
+      [subscription()],
+      [queue({ diffTotal: -1 })],
+      { now: '2026-08-31T12:01:00Z' },
+    );
+
+    expect(diagnostics.summary).toMatchObject({
+      totalKnownLag: 0,
+      reportedLag: 0,
+      unknownQueueCount: 1,
+    });
+  });
+
+  it('keeps the reported lag unknown without queue observations', () => {
+    const diagnostics = analyzeConsumerGroupHealth(group({ totalLag: -1 }), 
[subscription()], [], {
+      now: '2026-08-31T12:01:00Z',
+    });
+
+    expect(diagnostics.summary).toMatchObject({
+      totalKnownLag: 0,
+      reportedLag: null,
+    });
+  });
+
+  it('still warns about missing clients when only the known subtotal is 
positive', () => {
+    const diagnostics = analyzeConsumerGroupHealth(
+      group({ onlineInstances: 0, totalLag: -1, instances: [] }),
+      [subscription()],
+      [queue({ diffTotal: 17 }), queue({ broker: 'broker-b', queueId: 1, 
diffTotal: -1 })],
+      { now: '2026-08-31T12:01:00Z' },
+    );
+
+    expect(diagnostics.summary.reportedLag).toBeNull();
+    expect(diagnostics.issues.map((item) => 
item.code)).toContain('NO_ACTIVE_CLIENTS_WITH_LAG');
+  });
 });
diff --git a/web/src/utils/consumerGroupDiagnostics.ts 
b/web/src/utils/consumerGroupDiagnostics.ts
index e402512dc..83d923855 100644
--- a/web/src/utils/consumerGroupDiagnostics.ts
+++ b/web/src/utils/consumerGroupDiagnostics.ts
@@ -142,7 +142,7 @@ const heartbeatAgeSeconds = (lastHeartbeat: string | 
undefined, now: number): nu
 const knownLag = (progress: QueueProgress[]): number =>
   progress.reduce((sum, queue) => sum + (isLagAvailable(queue.diffTotal) ? 
queue.diffTotal : 0), 0);
 
-const reportedLag = (group: ConsumerGroup, fallback: number): number | null =>
+const reportedLag = (group: ConsumerGroup, fallback: number | null): number | 
null =>
   isLagAvailable(group.totalLag) ? group.totalLag : fallback;
 
 const topicCount = (group: ConsumerGroup, subscriptions: SubscriptionEntry[]): 
number => {
@@ -425,7 +425,8 @@ export const analyzeConsumerGroupHealth = (
     .map((queue) => queue.diffTotal)
     .filter((lag): lag is number => isLagAvailable(lag));
   const totalKnownLag = knownLag(progress);
-  const summaryReportedLag = reportedLag(group, totalKnownLag);
+  const allQueuesKnown = progress.length > 0 && knownQueueLags.length === 
progress.length;
+  const summaryReportedLag = reportedLag(group, allQueuesKnown ? totalKnownLag 
: null);
   const unknownQueueCount = progress.length - knownQueueLags.length;
   const heartbeatAges = (group.instances ?? [])
     .map((client) => heartbeatAgeSeconds(client.lastHeartbeat, now))
@@ -433,7 +434,7 @@ export const analyzeConsumerGroupHealth = (
   const issues = [
     ...subscriptionIssues(subscriptions),
     ...progressIssues(progress, knownQueueLags, unknownQueueCount, 
normalizedOptions),
-    ...runtimeIssues(group, summaryReportedLag, now, normalizedOptions),
+    ...runtimeIssues(group, summaryReportedLag ?? totalKnownLag, now, 
normalizedOptions),
   ];
   const status = maxStatus(issues);
 

Reply via email to