From a2b338dc03a2586a2c1099b309d1bb504ea58ed1 Mon Sep 17 00:00:00 2001 From: Benjamin Shafii Date: Tue, 3 Feb 2026 12:14:34 -0800 Subject: [PATCH] fix: pause polling when hidden and backoff server checks --- packages/app/src/app/app.tsx | 35 +++++++++++++++++-- .../app/src/app/components/status-bar.tsx | 17 +++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/packages/app/src/app/app.tsx b/packages/app/src/app/app.tsx index e26fee49..df32470a 100644 --- a/packages/app/src/app/app.tsx +++ b/packages/app/src/app/app.tsx @@ -294,6 +294,14 @@ export default function App() { setOpenworkServerSettings(readOpenworkServerSettings()); }); + createEffect(() => { + if (typeof document === "undefined") return; + const update = () => setDocumentVisible(document.visibilityState !== "hidden"); + update(); + document.addEventListener("visibilitychange", update); + onCleanup(() => document.removeEventListener("visibilitychange", update)); + }); + createEffect(() => { const pref = startupPreference(); const info = openworkServerHostInfo(); @@ -339,6 +347,7 @@ export default function App() { createEffect(() => { if (typeof window === "undefined") return; + if (!documentVisible()) return; const url = openworkServerBaseUrl().trim(); const auth = openworkServerAuth(); const token = auth.token; @@ -353,6 +362,13 @@ export default function App() { let active = true; let busy = false; + let timeoutId: number | undefined; + let delayMs = 10_000; + + const scheduleNext = () => { + if (!active) return; + timeoutId = window.setTimeout(run, delayMs); + }; const run = async () => { if (busy) return; @@ -362,23 +378,30 @@ export default function App() { if (!active) return; setOpenworkServerStatus(result.status); setOpenworkServerCapabilities(result.capabilities); + delayMs = + result.status === "connected" || result.status === "limited" + ? 10_000 + : Math.min(delayMs * 2, 60_000); + } catch { + delayMs = Math.min(delayMs * 2, 60_000); } finally { if (!active) return; setOpenworkServerCheckedAt(Date.now()); busy = false; + scheduleNext(); } }; run(); - const interval = window.setInterval(run, 10_000); onCleanup(() => { active = false; - window.clearInterval(interval); + if (timeoutId) window.clearTimeout(timeoutId); }); }); createEffect(() => { if (!isTauriRuntime()) return; + if (!documentVisible()) return; let active = true; const run = async () => { @@ -400,6 +423,7 @@ export default function App() { createEffect(() => { if (typeof window === "undefined") return; + if (!documentVisible()) return; if (!developerMode()) { setOpenworkServerDiagnostics(null); return; @@ -438,6 +462,7 @@ export default function App() { createEffect(() => { if (!isTauriRuntime()) return; if (!developerMode()) return; + if (!documentVisible()) return; let busy = false; @@ -464,6 +489,7 @@ export default function App() { setOwpenbotInfoState(null); return; } + if (!documentVisible()) return; let active = true; @@ -490,6 +516,7 @@ export default function App() { setOpenwrkStatusState(null); return; } + if (!documentVisible()) return; let active = true; @@ -525,6 +552,7 @@ export default function App() { const mountTime = Date.now(); const [lastKnownConfigSnapshot, setLastKnownConfigSnapshot] = createSignal(""); const [developerMode, setDeveloperMode] = createSignal(false); + const [documentVisible, setDocumentVisible] = createSignal(true); let markReloadRequiredRef: (reason: ReloadReason, trigger?: ReloadTrigger) => void = () => {}; let setReloadLastFinishedAtRef: (value: number) => void = () => {}; @@ -1392,6 +1420,7 @@ export default function App() { setDevtoolsWorkspaceId(null); return; } + if (!documentVisible()) return; const client = devtoolsOpenworkClient(); if (!client) { @@ -1430,6 +1459,7 @@ export default function App() { setOpenworkAuditError(null); return; } + if (!documentVisible()) return; const client = devtoolsOpenworkClient(); const workspaceId = devtoolsWorkspaceId(); @@ -2100,6 +2130,7 @@ export default function App() { createEffect(() => { if (typeof window === "undefined") return; + if (!documentVisible()) return; if (openworkReloadUnsupported()) return; const client = openworkServerClient(); const workspaceId = openworkServerWorkspaceId(); diff --git a/packages/app/src/app/components/status-bar.tsx b/packages/app/src/app/components/status-bar.tsx index 8b50801e..e68a9c41 100644 --- a/packages/app/src/app/components/status-bar.tsx +++ b/packages/app/src/app/components/status-bar.tsx @@ -22,6 +22,7 @@ type StatusBarProps = { export default function StatusBar(props: StatusBarProps) { const [owpenbotStatus, setOwpenbotStatus] = createSignal(null); + const [documentVisible, setDocumentVisible] = createSignal(true); const opencodeStatusMeta = createMemo(() => ({ dot: props.clientConnected ? "bg-green-9" : "bg-gray-6", @@ -162,12 +163,24 @@ export default function StatusBar(props: StatusBarProps) { setOwpenbotStatus(next); }; - onMount(() => { + createEffect(() => { + if (typeof document === "undefined") return; + const update = () => setDocumentVisible(document.visibilityState !== "hidden"); + update(); + document.addEventListener("visibilitychange", update); + onCleanup(() => document.removeEventListener("visibilitychange", update)); + }); + + createEffect(() => { + if (!documentVisible()) return; refreshOwpenbot(); const interval = window.setInterval(refreshOwpenbot, 15_000); + onCleanup(() => window.clearInterval(interval)); + }); + + onMount(() => { scheduleTips(6_000); onCleanup(() => { - window.clearInterval(interval); if (tipTimer) window.clearTimeout(tipTimer); if (tipHideTimer) window.clearTimeout(tipHideTimer); });