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

163 lines
3.7 KiB
Markdown

# 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:
```sh
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:
```txt
intervals created: 22
timeouts created: 11
interval fires: 148
timeout fires: 6
```
Most common timer registrations:
```txt
interval:200 7
timeout:12000 4
interval:60000 4
interval:250 4
interval:3000 4
interval:1000 2
```
In a 30s audit:
```txt
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:
```jsx
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:
```jsx
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:
```jsx
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:
```jsx
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.
## Recommended Path
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:
```sh
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.