From d871ccd7d4f48755b9bb5787ed39db71c904dfd8 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:30:42 +0800 Subject: [PATCH] fix(web): throttle workbench session list refresh pressure (#1914) --- web/hwlab-cloud-web/src/stores/workbench.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/web/hwlab-cloud-web/src/stores/workbench.ts b/web/hwlab-cloud-web/src/stores/workbench.ts index 8abc99dc..4295f81d 100644 --- a/web/hwlab-cloud-web/src/stores/workbench.ts +++ b/web/hwlab-cloud-web/src/stores/workbench.ts @@ -27,8 +27,9 @@ const ACTIVE_TURN_GAP_MAX_DELAY_MS = 5_000; const SESSION_LIST_PAGE_LIMIT = 20; const WORKBENCH_READ_HYDRATION_CONCURRENCY = 3; const WORKBENCH_READ_FAILURE_COOLDOWN_MS = 5_000; -const SESSION_LIST_REALTIME_REFRESH_DELAY_MS = 1_200; -const SESSION_LIST_TERMINAL_REFRESH_DELAY_MS = 400; +const SESSION_LIST_REALTIME_REFRESH_DELAY_MS = 5_000; +const SESSION_LIST_TERMINAL_REFRESH_DELAY_MS = 1_500; +const SESSION_LIST_MIN_REFRESH_INTERVAL_MS = 15_000; interface HydrateOptions { sessionId?: string | null; @@ -80,6 +81,7 @@ export const useWorkbenchStore = defineStore("workbench", () => { let activeTurnGapTimer: number | null = null; const sessionListRefreshInFlight = new Map>(); const sessionListRefreshTimers = new Map(); + const sessionListLastRefreshAtByKey = new Map(); let workbenchReadHydrationActive = 0; const workbenchReadHydrationQueue: Array<() => void> = []; const workbenchReadCooldownUntilByKey = new Map(); @@ -239,7 +241,7 @@ export const useWorkbenchStore = defineStore("workbench", () => { recordWorkbenchLoadingState({ scope: "session_detail", active: false, reason: "select_session", sessionId: selected.sessionId }); recordWorkbenchLoadingState({ scope: "workbench", active: false, reason: "select_session", sessionId: selected.sessionId }); error.value = null; - await refreshSessions(selected.sessionId); + await refreshSessions(selected.sessionId, { force: true }); finishWorkbenchSessionSwitchFullLoad(selected.sessionId, "ok"); return activeSessionId.value === selected.sessionId; } @@ -264,7 +266,7 @@ export const useWorkbenchStore = defineStore("workbench", () => { return; } forgetSession(sessionId); - await refreshSessions(null); + await refreshSessions(null, { force: true }); const next = sessions.value.find((session) => !isArchivedSession(session)) ?? null; replaceActiveSessionSelection(next?.sessionId ?? null); currentRequest.value = null; @@ -275,12 +277,16 @@ export const useWorkbenchStore = defineStore("workbench", () => { restartRealtime("delete-current-session"); } - async function refreshSessions(includeSessionId: string | null = activeSessionId.value): Promise { + async function refreshSessions(includeSessionId: string | null = activeSessionId.value, options: { force?: boolean } = {}): Promise { const requestIncludeSessionId = firstNonEmptyString(includeSessionId); const requestLimit = currentSessionListLimit(); const requestKey = sessionListRefreshKey(requestIncludeSessionId, requestLimit); const existing = sessionListRefreshInFlight.get(requestKey); if (existing) return existing; + const now = Date.now(); + const lastRefreshAt = sessionListLastRefreshAtByKey.get(requestKey) ?? 0; + if (options.force !== true && lastRefreshAt > 0 && now - lastRefreshAt < SESSION_LIST_MIN_REFRESH_INTERVAL_MS) return; + sessionListLastRefreshAtByKey.set(requestKey, now); const refresh = refreshSessionsNow(requestIncludeSessionId, requestLimit).finally(() => { if (sessionListRefreshInFlight.get(requestKey) === refresh) sessionListRefreshInFlight.delete(requestKey); }); @@ -315,10 +321,13 @@ export const useWorkbenchStore = defineStore("workbench", () => { } const existing = sessionListRefreshTimers.get(requestKey); if (existing) window.clearTimeout(existing); + const lastRefreshAt = sessionListLastRefreshAtByKey.get(requestKey) ?? 0; + const cooldownMs = lastRefreshAt > 0 ? Math.max(0, SESSION_LIST_MIN_REFRESH_INTERVAL_MS - (Date.now() - lastRefreshAt)) : 0; + const boundedDelayMs = Math.max(0, Math.trunc(delayMs), cooldownMs); const timer = window.setTimeout(() => { sessionListRefreshTimers.delete(requestKey); void refreshSessions(requestIncludeSessionId); - }, Math.max(0, Math.trunc(delayMs))); + }, boundedDelayMs); sessionListRefreshTimers.set(requestKey, timer); }