Skip to content

perf: shed background polling that crashes the gateway#55

Merged
outsourc-e merged 6 commits into
mainfrom
fix/gateway-pressure-cleanup
May 14, 2026
Merged

perf: shed background polling that crashes the gateway#55
outsourc-e merged 6 commits into
mainfrom
fix/gateway-pressure-cleanup

Conversation

@outsourc-e

Copy link
Copy Markdown
Owner

Why

The Clawsuite dashboard was firing ~120 background requests/minute at the OCPlatform gateway just sitting on a page (50+ active timers across all the dashboard hooks). On laptops and on the gateway side this consistently produced lag and outright crashes. Eric reported this was bad enough that he stopped using the app.

What this branch does

Three classes of fix:

1. Polling intervals — lazier + lighter

  • use-dashboard-data: sessions 30s→120s, gateway-status 15s→60s, session-status 30s→180s
  • refetchOnWindowFocus: false + refetchOnReconnect: false on the heavy queries
  • use-streaming-message: accepted 30s→90s, handoff 45s→180s so normal gateway lag doesn't falsely mark messages as failed

2. Hot health probes removed

  • GatewayConnectionBanner had its own pingGateway() loop that was too noisy and produced false-offline banners while chat was usable. Component now returns null until the health logic is rewritten to distinguish slow usage/session RPCs from actual gateway loss.
  • full-outputs-view: 326-line legacy aggregate output panel deleted

3. Streaming path made reliable-first

  • use-streaming-message now lands the user message reliably via /api/send first, then upgrades to streaming; removes the brittle stream-first fallback that was eating retries

4. Server lifecycle

  • gateway.ts shutdown handler no longer process.exit(0) during vite dev, so reload churn doesn't take down the whole dev server

5. Routing tidy

  • /operations route + sidebar entry restored
  • Misc small fixes: dashboard overflow, mobile tab bar, swipe nav, chat-sidebar active states

Net diff

16 files, +214 / −611 (≈400 lines removed).

Validation

  • pnpm build
  • pnpm test — 9/9 passing ✓
  • src/routes/api/send.ts restored from main after an interrupted in-progress diff had stubbed it to a hello-world

Follow-up (separate PR)

The right long-term fix is to replace the 50+ polling hooks with one shared SSE stream from /api/events for gateway-side state changes. That's a bigger refactor; this branch is the surgical polling-pressure relief so the app is usable today.

Closes the regression where dashboard usage repeatedly crashed the OCPlatform gateway.

Aurora added 6 commits May 14, 2026 02:58
The dashboard was firing ~120 background requests/minute at the gateway
just sitting on a page. Three classes of fix in one branch:

Polling intervals (lazier + lighter):
- use-dashboard-data: sessions 30s→120s, gateway-status 15s→60s,
  session-status 30s→180s; refetchOnWindowFocus/Reconnect disabled
- use-streaming-message: accepted 30s→90s, handoff 45s→180s so normal
  gateway lag does not falsely mark messages as failed

Hot health probes that compounded the load (removed/disabled):
- GatewayConnectionBanner — its own pingGateway loop is too noisy and
  yields false-offline banners while chat is usable; component returns
  null until the health logic is rewritten
- full-outputs-view: 326-line legacy aggregate output panel deleted

Streaming path:
- use-streaming-message now lands the user message reliably via /api/send
  first, then upgrades to streaming; removes the brittle stream-first
  fallback that was eating retries

Server lifecycle:
- gateway.ts shutdown handler no longer process.exit(0) during vite dev,
  so reload churn does not take down the whole dev server

Routing tidy:
- /operations route + sidebar entry restored so it does not 404 after
  Agents Hub moved
- Misc small fixes: dashboard overflow, mobile tab bar, swipe nav,
  chat-sidebar active states

Net diff: 16 files, ~-400 lines.

Validation:
- pnpm build ✓
- pnpm test (9/9) ✓
…ppress for auth

The 'Gateway unreachable' banner was firing on every chat open during the
1-2s window before SSE connected, even when the gateway was actually fine.
It also fired on auth/pairing errors that should be routed through the
setup wizard, not a chat-screen toast.

Three changes:
- Require >=2 consecutive status-query failures before showing the banner
  (single transient timeout no longer flashes a scary toast)
- Suppress for status 401/403 and auth/pair phrases — those belong to the
  setup wizard, not chat
- Drop refetchOnWindowFocus / refetchOnReconnect on the status query;
  background interval is now 120s (was 60s) since SSE is the real signal

The banner remains intact for the real case: gateway truly down for 2+
consecutive probes and SSE not connected.
Two global background loops were still pounding the gateway even off-dashboard:

- SystemMetricsFooter polled /api/system-metrics every 5s everywhere,
  and /api/system-metrics itself called gatewayRpc('status').
- WorkspaceShell polled /api/sessions every 15s on every route.

Fix:
- SystemMetricsFooter now takes enabled prop and is only mounted on /dashboard;
  its interval is 30s (was 5s)
- WorkspaceShell sessions query now polls at 60s on chat/dashboard and 120s
  elsewhere; refetchOnWindowFocus/Reconnect disabled; staleTime raised to 60s

This should remove the last app-wide background gateway hammering while still
keeping the useful surfaces fresh enough.
…probe spam

Workspace pairs cleanly with the gateway because it has ONE source of truth
(the live SSE connection) and only falls back to an HTTP status probe when
SSE actually disconnects. Clawsuite had three competing probes (ping,
gateway/status, system-metrics's embedded status RPC) all on intervals, which
tripped the OCPlatform gateway circuit breaker within ~30s of idle.

Changes:
- chat-screen.gatewayStatusQuery: enabled only when SSE is NOT connected;
  no refetch interval; staleTime 120s. The query runs once on SSE drop, not
  on a timer.
- chat-composer models query: stop polling. Models rarely change; staleTime
  5min, refetch on demand.
- chat-sidebar recent-issues indicator: 20s -> 60s + refetchOnWindowFocus off.
- use-chat-sessions: 30s -> 60s + refetchOnWindowFocus off.

After this change, 35s of idle on the chat screen produces ZERO gateway RPC
timeouts in the dev log (was tripping the circuit breaker on every cycle).
On mobile via Tailscale, the auth-check query could stall the whole app on
the loading splash for 10+ seconds:
  - 5s fetch timeout + 2 retries with 1s delay = 13s worst case
  - meanwhile dashboard queries fire in parallel and pile up RPCs

Three changes:
- auth-check fetch timeout 5s -> 2s (it's a local endpoint, should be <100ms)
- retry 2 -> 1, retryDelay 1000 -> 500ms
- new splashTimedOut state: if auth-check hasn't responded after 3.5s, we
  proceed optimistically as authenticated=true, authRequired=false (the
  underlying middleware still enforces real auth; this just stops the splash
  from holding the whole UI hostage on a slow network)

Defaults also flipped: authenticated defaults to true, authRequired to false,
so a missing auth response no longer assumes the worst-case login screen.
Root cause of the 'Could not connect to ClawSuite server' crash screen:
- workspace-shell treated any /api/auth-check fetch miss as a fatal app error
- in practice the dev server stayed healthy and user messages still sent
- result: a transient local fetch hiccup looked like a full app crash

Fix:
- remove the fatal full-screen authQuery.isError blocker entirely
- keep the app live and render a small non-blocking warning banner instead
- retain Retry affordance so the auth-check can be re-run without nuking the UI

This matches the intended behavior better: if the shell is up and the app is
still functioning, do not blank the whole screen because one auth probe had a
bad moment.
@outsourc-e outsourc-e merged commit 9ef1ad6 into main May 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant