-
Notifications
You must be signed in to change notification settings - Fork 16
Open
Description
Problem
The coding_cli_refresh operation in server/coding-cli/session-indexer.ts processes session files synchronously, blocking the Node.js event loop for extended periods. This causes cascading performance degradation including terminal input lag, WebSocket disconnections, and UI freezing.
Evidence from Production Logs
{"event":"coding_cli_refresh","durationMs":4381.55} // 4.4 second refresh
{"event":"perf_system","eventLoopMax":6895.44} // 6.9s event loop block
{"event":"ws_backpressure_close"} // Connection killed
{"event":"terminal_input_lag","lagMs":2516} // 2.5s input delay
Scale of the Problem
- 8,206 session files being scanned (5,573 Claude + 2,633 Codex)
- 6.6GB of session data in
~/.claude/projectsand~/.codex - Refresh times: 500ms - 4,400ms
- Event loop blocking: up to 6,895ms (nearly 7 seconds)
- Server uptime before restart: 20+ hours
Root Cause
The session indexer at server/coding-cli/session-indexer.ts:630-800 uses synchronous file I/O:
- Synchronous file reads -
fs.readFileSyncor similar blocks the event loop - Synchronous JSON parsing - Large JSONL files parsed synchronously
- Insufficient yielding -
yieldToEventLoop()every 200 files is not enough with 8,000+ files - No parallelization - Single-threaded processing of all files
The current yieldToEventLoop() approach helps but doesn't prevent multi-second blocks because each individual file operation can still take substantial time.
Timeline of Degradation
| Time | Event Loop Max | Issue |
|---|---|---|
| 21:35:26 | 4,836ms | Major block during refresh |
| 23:47:59 | 6,895ms | Worst block - heap jumped 220→608MB |
| 21:58-22:04 | 300-700ms | Sustained high latency |
Proposed Solution
- Use async file operations - Replace sync reads with
fs.promises.readFile - Worker threads - Offload file parsing to worker threads to avoid blocking main thread
- Batched processing - Process files in smaller batches with proper async gaps
- Incremental indexing - Only re-index changed files using mtime comparison
- Lazy loading - Don't load full session content upfront, just metadata
Impact
- High - This is the primary cause of Freshell becoming unusably slow after extended uptime
- Affects all users with large numbers of Claude/Codex sessions
- Gets progressively worse as more sessions accumulate
Related
- Contributes to WebSocket backpressure issues
- Related to memory leak in session state
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels