Problem
Tracing (#49 / #138) surfaced that GET /api/sysinfo has a p95 around 4 seconds. softwareVersions() in internal/system/system.go runs all 13 external probes (zfs version, ansible-playbook --version, smartctl --version, …) via exec on every request — and the frontend calls loadAll() (which includes sysinfo) on page load, every 60 s per open tab (static/app.js), every 30 s when SSE is down, and on every SSE reconnect. A tab left open 24/7 means ~1440 full probe rounds per day.
Proposal
Cache the probe results with a short TTL (e.g. 60 s), or probe once at startup and refresh lazily/on demand — installed software changes rarely. platformWarnings() (kldstat, sysrc, crontab reads) is comparatively cheap but could share the same cache.
Keep the response shape unchanged (software array with required/feature from #135).
Evidence
Span metrics via Tempo metrics-generator: GET /api/sysinfo p95 ≈ 4 s vs sub-second for almost every other read endpoint.
Problem
Tracing (#49 / #138) surfaced that
GET /api/sysinfohas a p95 around 4 seconds.softwareVersions()ininternal/system/system.goruns all 13 external probes (zfs version,ansible-playbook --version,smartctl --version, …) viaexecon every request — and the frontend callsloadAll()(which includes sysinfo) on page load, every 60 s per open tab (static/app.js), every 30 s when SSE is down, and on every SSE reconnect. A tab left open 24/7 means ~1440 full probe rounds per day.Proposal
Cache the probe results with a short TTL (e.g. 60 s), or probe once at startup and refresh lazily/on demand — installed software changes rarely.
platformWarnings()(kldstat, sysrc, crontab reads) is comparatively cheap but could share the same cache.Keep the response shape unchanged (
softwarearray withrequired/featurefrom #135).Evidence
Span metrics via Tempo metrics-generator:
GET /api/sysinfop95 ≈ 4 s vs sub-second for almost every other read endpoint.