Files
MultiRoombaRover/perf/issues/007-timers-and-polling.md
T
2026-06-12 14:35:45 -04:00

3.7 KiB

FIXED!

Issue 007: Timers and Polling Cleanup

Summary

The / page creates multiple intervals and timeouts. They are not the dominant problem, but they contribute to steady background work and can wake components even when hidden.

Severity

Low to medium.

Address after the larger structural issues unless a specific timer is found to be hot.

Affected Files

Known or likely timer users:

  • webui/src/components/AlertFeed/index.jsx
  • webui/src/components/ReplaySourcesPanel/index.jsx
  • webui/src/components/HudOverlays/TurnsOverlay/index.jsx
  • webui/src/components/RoverQueuesPanel/index.jsx
  • webui/src/components/ModeGateOverlay/index.jsx
  • webui/src/components/SocketConnectionPill/index.jsx
  • webui/src/controls/ControlContext.jsx horn heat interval
  • webui/src/controls/overcurrentLimiter.js

Evidence

Artifact:

perf/results/2026-06-11T03-22-44-714Z-root-runtime/root-runtime-report.json

In an 18s / audit at mobile viewport with 6x CPU throttle:

intervals created:     22
timeouts created:      11
interval fires:        148
timeout fires:         6

Most common timer registrations:

interval:200      7
timeout:12000     4
interval:60000    4
interval:250      4
interval:3000     4
interval:1000     2

In a 30s audit:

interval fires: 593

Why This Matters

Timers wake the main thread. On a fast desktop they disappear into the noise; on a throttled mobile CPU, timers can combine with socket traffic and React work to create visible stalls.

The timer issue is not that any one interval is terrible. It is that many UI elements keep time independently.

Likely Sources

ReplaySourcesPanel

Cooldown display:

const interval = setInterval(update, 250);

Only needed while cooldown is active and panel is visible.

AlertFeed

Likely uses a frequent interval for alert lifetimes. This should only run while alerts exist.

TurnsOverlay / RoverQueuesPanel

Countdown displays often use setInterval(() => setNow(Date.now()), 250 or 1000).

ControlContext Horn Heat

Horn heat interval at 100ms only runs when horn is active/cooling:

const tickMs = 100;
const interval = setInterval(...)

This is probably okay, but verify it only runs when needed.

Fix Strategies

Option A: Visibility-Gate Timers

Only run panel-specific timers when the panel is visible/open.

Example:

if (!isVisible || !needsCountdown) return;

Option B: Coarse Intervals

Use 1000ms for human-readable countdowns unless sub-second precision matters.

Replay cooldowns and queue countdowns probably do not need 250ms.

Option C: Shared Clock Store

Instead of each component creating its own interval, create one shared clock:

useClock(1000)
useClock(250)

Then multiple components can share a single interval.

Option D: CSS Animations for Pure Visual Expiry

For alert progress bars, use CSS animation if the UI does not need React state each tick.

After major fixes, rerun the runtime audit. If intervals still show high:

  1. Increase replay cooldown interval from 250ms to 1000ms.
  2. Gate timers by tab visibility.
  3. Create a shared clock hook for countdown UI.
  4. Convert alert lifetime visuals to CSS where possible.

Validation

Run:

CPU_THROTTLE=6 VIEWPORT=390x844 MOBILE=1 SAMPLE_MS=30000 node perf/live-root-runtime-audit.mjs https://rover.otter.land/ perf/results

Expected:

  • lower intervals
  • lower intervalFires
  • no visible regression in countdowns/alerts

Risks

  • Timers used for control safety should not be slowed without careful review.
  • Alert expiration should still happen reliably.
  • Queue/turn countdowns can update less often, but should not become misleading.