mirror of
https://github.com/exo-explore/exo.git
synced 2026-05-19 20:25:06 -04:00
Fixes #2004. `ClusterStateService` polls `/state` at 2 Hz via `URLSession.shared`, which keeps an on-disk `URLCache` attached by default. Every polled response body gets persisted under `~/Library/Caches/exolabs.EXO/`, sustaining ~500–620 KB/sec of file-backed memory dirtied — far above macOS's ~25 KB/sec per-process daily-average baseline. Six microstackshot reports observed on a single Mac Studio M3 Ultra over eight days, with one 15-hour run accumulating 34.36 GB of cache writes. Heaviest stack on every diagnostic report (96–98% of samples): ``` _dispatch_workloop_worker_thread → _dispatch_block_async_invoke2 → __CFURLCache::CreateAndStoreCacheNode → write ``` Full diagnostic data and analysis in #2004. ## What changed `ClusterStateService` now defaults to an ephemeral, non-caching `URLSession` instead of `URLSession.shared`. Cluster-state responses are time-sensitive and small; nothing benefits from being cached on disk. ```swift private static func makeNonCachingSession() -> URLSession { let config = URLSessionConfiguration.ephemeral config.urlCache = nil config.requestCachePolicy = .reloadIgnoringLocalCacheData return URLSession(configuration: config) } ``` The existing per-request `request.cachePolicy = .reloadIgnoringLocalCacheData` calls are kept as defense in depth — they only affect read behavior, but harmless to leave alongside the session-level config. ## Scope - **Behavioral**: none. Polled requests still go out at the same cadence; responses still parse the same; no semantic change to any API surface. - **Test injection**: the `session:` parameter remains in `init`, so tests can still inject a custom mock session unchanged. - **`BugReportService` and other `URLSession.shared` callers**: untouched. If maintainers prefer an app-wide URLCache disable instead, happy to switch the approach (issue body has the alternative spelled out). ## Verification Verified locally that compiling EXO with this change produces a working menubar app and `ClusterStateService` continues to fetch state correctly. After ~30 min of idle polling, no new entries in `/Library/Logs/DiagnosticReports/EXO_*.diag` and no growth in `~/Library/Caches/exolabs.EXO/`. ## Test plan - [ ] Build EXO from this branch on macOS 26.4 - [ ] Launch, let cluster state polling run for 30+ min - [ ] Confirm no new microstackshot diagnostic reports - [ ] Confirm `~/Library/Caches/exolabs.EXO/Cache.db*` does not grow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Jordan Miller <jordan.d.miller@gmail.com>