mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
166 lines
4.2 KiB
Markdown
166 lines
4.2 KiB
Markdown
# FIXED!
|
|
# Issue 003: High-Volume Socket Log Stream
|
|
|
|
## Summary
|
|
|
|
The `/` page receives a very high volume of `log:entry` socket messages. These update the
|
|
global session store even when logs are not the primary visible task.
|
|
|
|
This is not the single biggest CPU stack item, but it is a major source of live update
|
|
pressure on low-end devices.
|
|
|
|
## Severity
|
|
|
|
Medium-high.
|
|
|
|
Fix after listener/context work, unless logs are known to be unusually noisy in production.
|
|
|
|
## Affected Files
|
|
|
|
- `webui/src/context/SessionContext.jsx`
|
|
- `webui/src/components/LogPanel/index.jsx`
|
|
- Server log emission paths, depending on where `log:entry` is emitted
|
|
|
|
## 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
|
|
log:entry count: 850
|
|
log:entry bytes: 185,008
|
|
```
|
|
|
|
Artifact:
|
|
|
|
```sh
|
|
perf/results/2026-06-11T03-21-51-263Z-root-runtime/root-runtime-report.json
|
|
```
|
|
|
|
In a 30s audit, among the most recent sampled 1000 WebSocket messages:
|
|
|
|
```txt
|
|
log:entry count: 526
|
|
log:entry bytes: 111,535
|
|
```
|
|
|
|
In `SessionContext.jsx`, each log entry does:
|
|
|
|
```jsx
|
|
function handleLogEntry(entry) {
|
|
setState((prev) => ({ ...prev, logs: [...prev.logs.slice(-199), entry] }));
|
|
}
|
|
```
|
|
|
|
This creates a new session state object and a new logs array for every log message.
|
|
|
|
## Why This Matters
|
|
|
|
Even if `LogPanel` is not visible or not currently selected, `SessionContext` still processes
|
|
the update. Every session subscriber selector is evaluated on each `setState`.
|
|
|
|
At 850 log messages in 18s, this is roughly 47 log entries per second.
|
|
|
|
On a powerful desktop this is fine. On a weaker phone or low-end laptop, it becomes steady
|
|
background pressure.
|
|
|
|
## Likely Cause
|
|
|
|
The server appears to broadcast operational logs very frequently. The client stores the last
|
|
200 logs globally.
|
|
|
|
The `/` page includes `LogPanel` under settings and may also have other components depending
|
|
on session state.
|
|
|
|
## Fix Strategies
|
|
|
|
### Option A: Do Not Subscribe to Logs Unless Log UI Is Visible
|
|
|
|
Best conceptual fix:
|
|
|
|
- Add an explicit client event like `log:subscribe` / `log:unsubscribe`.
|
|
- Only subscribe when `LogPanel` is open or user is admin.
|
|
- For ordinary mobile control users, skip logs entirely.
|
|
|
|
### Option B: Batch Log Entries Client-Side
|
|
|
|
Keep receiving logs, but batch state updates:
|
|
|
|
```jsx
|
|
const pendingLogsRef = useRef([]);
|
|
const flushTimerRef = useRef(null);
|
|
|
|
function handleLogEntry(entry) {
|
|
pendingLogsRef.current.push(entry);
|
|
if (flushTimerRef.current) return;
|
|
flushTimerRef.current = setTimeout(() => {
|
|
const batch = pendingLogsRef.current.splice(0);
|
|
flushTimerRef.current = null;
|
|
setState((prev) => ({
|
|
...prev,
|
|
logs: [...prev.logs, ...batch].slice(-200),
|
|
}));
|
|
}, 250);
|
|
}
|
|
```
|
|
|
|
This changes 47 state updates/sec into about 4 updates/sec.
|
|
|
|
### Option C: Store Logs in a Separate External Store
|
|
|
|
Move logs out of main `SessionContext` so unrelated session consumers are not touched by
|
|
log spam.
|
|
|
|
For example:
|
|
|
|
```jsx
|
|
LogStoreProvider
|
|
useLogEntries()
|
|
```
|
|
|
|
This isolates log updates from user/roster/session state.
|
|
|
|
### Option D: Server-Side Sampling or Severity Filtering
|
|
|
|
Only send:
|
|
|
|
- warnings/errors by default
|
|
- full logs to admin/log panel subscribers
|
|
- sampled info/debug entries
|
|
|
|
## Recommended Path
|
|
|
|
Start with client batching. It is low-risk and easy to validate.
|
|
|
|
Then consider subscription gating if logs are not essential for normal users.
|
|
|
|
## 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
|
|
```
|
|
|
|
The socket `log:entry` count may remain high if only batching client-side, but UI state
|
|
updates should reduce. To measure batching directly, add temporary counters in
|
|
`SessionContext` or extend the audit to count React commits after local changes.
|
|
|
|
Expected user-visible perf improvements:
|
|
|
|
- lower `ScriptDuration`
|
|
- lower `TaskDuration`
|
|
- fewer repeated DOM commits if log updates were causing broad subscribers to render
|
|
|
|
## Risks
|
|
|
|
- Logs may be used for operator visibility during incidents.
|
|
- Batching can delay log display by 100-500ms. That should be acceptable for UI logs.
|
|
- Subscription gating requires server/client protocol changes.
|
|
|