← Back to PRs

#4664: fix: per-session metadata files to eliminate lock contention

by tsukhani open 2026-01-30 13:46 View on GitHub →
## Summary Instead of all sessions sharing a single `sessions.json` with a global file lock, each session now gets its own `.meta.json` file for frequent updates. This eliminates lock contention when multiple sessions are active simultaneously. ## Problem When chatting on multiple channels (e.g., Slack and Telegram) simultaneously, sessions would block each other because `updateSessionStoreEntry` required an exclusive lock on the shared `sessions.json` file. ## Solution - New `per-session-store.ts` with atomic write functions for per-session `.meta.json` files - `updateSessionStoreEntry` now writes to per-session files without acquiring the global lock - Background debounced sync keeps `sessions.json` in sync (best-effort, 5s debounce) - Fallback to locked update for legacy entries without sessionId ## Testing - [x] Tested locally with concurrent Slack and Telegram sessions - [x] Linter passes ## AI Assistance 🤖 This PR was AI-assisted (Claude). The fix was identified by tracing the session update flow and finding the global lock bottleneck reported in #3092. Fixes #3092 <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR reduces contention on `sessions.json` by introducing per-session `.meta.json` files and updating `updateSessionStoreEntry` to write frequent updates to those per-session files without taking the global session-store lock. A debounced background task periodically syncs the updated entries back into `sessions.json` under the existing lock, and legacy entries without `sessionId` continue to use the locked update path. Overall this aligns with the repository’s existing atomic-write approach for `sessions.json`, but the new flow introduces some correctness/portability edge cases (agentId path parsing, and concurrent updates to the same session) that are worth addressing before relying on it broadly. <h3>Confidence Score: 3/5</h3> - This PR is reasonably safe to merge but has a couple of correctness/portability edge cases that could surface under concurrency or non-Windows paths. - The overall design (per-session files + best-effort sync) is sound and localized, but `extractAgentIdFromStorePath` appears path-separator dependent, and the per-session update path can lose updates if multiple writers touch the same session concurrently because it’s a read-merge-write without per-session serialization. The rest are minor robustness concerns (file permissions parity, unbounded pending syncs). - src/config/sessions/store.ts, src/config/sessions/per-session-store.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs