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 af47c9697 fix(consumer): refresh the subscription verdict on the 2s 
modal auto-refresh (#4593)
af47c9697 is described below

commit af47c96977da261a8ff580ea7a49340f14c6774b
Author: Zhao Jianing <[email protected]>
AuthorDate: Mon Sep 21 21:03:51 2026 +0800

    fix(consumer): refresh the subscription verdict on the 2s modal 
auto-refresh (#4593)
    
    The consumer group detail modal advertises a 2s auto-refresh in its header 
and repeats it next to the diagnostics verdict, but the interval tick only 
awaited `refreshConsumerGroup` and `loadProgress`. `loadSubscriptions` returns 
early on its per-group cache unless `force` is set, and the call made when the 
modal opens does not force it, so the subscription-consistency verdict — the 
part of the diagnostics the copy actually refers to — stayed frozen for the 
modal's whole lifetime and o [...]
    
    `loadSubscriptions` gains a `silent` parameter mirroring the one 
`loadProgress` already had: it skips the loading flag and the error toast but 
still records `subscriptionErrorByGroup`, so the existing subscription-failure 
alert does not regress. The tick now awaits a forced, silent subscription 
refresh after the progress refresh, and the callback joined the effect's 
dependency list. The `inFlight` guard still prevents overlapping ticks.
    
    Because `loadSubscriptions` depends on `subscriptionsByGroup`, each tick 
rebuilds the interval, so the cadence becomes "2s after the previous tick 
finished" — the same shape `loadProgress` already had.
---
 .../pages/instance/__tests__/ConsumerPage.test.tsx | 49 ++++++++++++++++++++++
 web/src/pages/instance/consumer.tsx                | 20 ++++++---
 2 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/web/src/pages/instance/__tests__/ConsumerPage.test.tsx 
b/web/src/pages/instance/__tests__/ConsumerPage.test.tsx
index eee564664..7ffd8d61d 100644
--- a/web/src/pages/instance/__tests__/ConsumerPage.test.tsx
+++ b/web/src/pages/instance/__tests__/ConsumerPage.test.tsx
@@ -1204,6 +1204,55 @@ describe('Consumer page', () => {
     expect(consumerService.getConsumerSubscriptions).toHaveBeenCalledTimes(2);
   });
 
+  it('refreshes the subscription verdict on the 2s modal auto-refresh', async 
() => {
+    vi.mocked(consumerService.getConsumerSubscriptions)
+      .mockResolvedValueOnce([
+        {
+          topic: 'remote-topic',
+          expression: '*',
+          type: 'NORMAL',
+          filterMode: '全量',
+          consistency: 'consistent',
+        },
+        {
+          topic: 'stale-topic',
+          expression: 'important',
+          type: 'NORMAL',
+          filterMode: 'Tag 过滤',
+          consistency: 'inconsistent',
+        },
+      ])
+      .mockResolvedValueOnce([
+        {
+          topic: 'remote-topic',
+          expression: '*',
+          type: 'NORMAL',
+          filterMode: '全量',
+          consistency: 'consistent',
+        },
+        {
+          topic: 'stale-topic',
+          expression: 'important',
+          type: 'NORMAL',
+          filterMode: 'Tag 过滤',
+          consistency: 'consistent',
+        },
+      ]);
+
+    const user = userEvent.setup();
+    renderWithProviders(<ConsumerPage />);
+
+    await user.click(await screen.findByRole('button', { name: /详情/ }));
+
+    // The modal advertises that the diagnostic result refreshes every 2 
seconds. Without any
+    // further user action the subscription consistency verdict must be 
re-checked alongside
+    // the progress table, not stay frozen at whatever the first load returned.
+    await waitFor(() => 
expect(consumerService.getConsumerSubscriptions).toHaveBeenCalledTimes(2), {
+      timeout: 10000,
+    });
+    expect(await screen.findByText('全部 2 个订阅配置一致')).toBeInTheDocument();
+  });
+
   it('keeps unknown consistency values separate from mismatches', async () => {
     vi.mocked(consumerService.getConsumerSubscriptions).mockResolvedValue([
       {
diff --git a/web/src/pages/instance/consumer.tsx 
b/web/src/pages/instance/consumer.tsx
index d09286875..2927d3c01 100644
--- a/web/src/pages/instance/consumer.tsx
+++ b/web/src/pages/instance/consumer.tsx
@@ -408,10 +408,12 @@ const ConsumerPageContent = ({
   }, [autoRefresh, selectedInstanceId, triggerRefresh]);
 
   const loadSubscriptions = useCallback(
-    async (groupName: string, force = false) => {
+    async (groupName: string, force = false, silent = false) => {
       const cacheKey = diagnosticCacheKey(selectedInstanceId, groupName);
       if (!force && subscriptionsByGroup[cacheKey]) return;
-      setSubscriptionLoadingByGroup((prev) => ({ ...prev, [cacheKey]: true }));
+      if (!silent) {
+        setSubscriptionLoadingByGroup((prev) => ({ ...prev, [cacheKey]: true 
}));
+      }
       setSubscriptionErrorByGroup((prev) => ({ ...prev, [cacheKey]: false }));
       try {
         const subscriptions = await getConsumerSubscriptions(
@@ -421,9 +423,13 @@ const ConsumerPageContent = ({
         setSubscriptionsByGroup((prev) => ({ ...prev, [cacheKey]: 
subscriptions }));
       } catch {
         setSubscriptionErrorByGroup((prev) => ({ ...prev, [cacheKey]: true }));
-        message.error(t('consumer.fetchSubscriptionsFailed', { name: groupName 
}));
+        if (!silent) {
+          message.error(t('consumer.fetchSubscriptionsFailed', { name: 
groupName }));
+        }
       } finally {
-        setSubscriptionLoadingByGroup((prev) => ({ ...prev, [cacheKey]: false 
}));
+        if (!silent) {
+          setSubscriptionLoadingByGroup((prev) => ({ ...prev, [cacheKey]: 
false }));
+        }
       }
     },
     [subscriptionsByGroup, t, selectedInstanceId],
@@ -463,6 +469,10 @@ const ConsumerPageContent = ({
           setSelectedGroup((prev) => (prev && prev.name === groupName ? 
refreshed : prev));
         }
         await loadProgress(groupName, true, true);
+        // The modal advertises "每 2s 自动刷新" for the whole diagnostic result, 
which includes
+        // the subscription consistency verdict, not only the progress table. 
Refresh it silently
+        // so a failing backend does not toast every 2s and the check spinner 
does not flicker.
+        await loadSubscriptions(groupName, true, true);
       } catch {
         // 自动刷新失败静默处理,避免每 2s 弹错
       } finally {
@@ -471,7 +481,7 @@ const ConsumerPageContent = ({
     };
     const interval = window.setInterval(() => void tick(), 2000);
     return () => window.clearInterval(interval);
-  }, [modalOpen, selectedGroupName, selectedInstanceId, loadProgress]);
+  }, [modalOpen, selectedGroupName, selectedInstanceId, loadProgress, 
loadSubscriptions]);
 
   /* ─── Filtered & sorted data ─── */
   const filtered = useMemo(() => {

Reply via email to