fix: add idle-timeout Instance disposal for serve mode memory#16616
fix: add idle-timeout Instance disposal for serve mode memory#16616sjawhar wants to merge 2 commits intoanomalyco:devfrom
Conversation
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate/Related PRs Found:
These are related to memory/disposal management but have different scopes. #16616 (current PR) appears to be the most comprehensive solution targeting the specific serve mode instance caching issue with idle-timeout disposal. |
|
Why does yours have 58 files to fix this? Majority being MD? |
b2326b3 to
2b44b94
Compare
|
Good catch — those were internal tooling files (.sisyphus/) that shouldn't have been tracked. Cleaned up, the diff now only contains the 2 relevant source files (instance.ts + flag.ts) plus the test file. |
677af75 to
1f4520d
Compare
Addresses the remaining memory leaks identified in anomalyco#16697 by consolidating the best fixes from 23+ open community PRs into a single coherent changeset. Fixes consolidated from PRs: anomalyco#16695, anomalyco#16346, anomalyco#14650, anomalyco#15646, anomalyco#13186, anomalyco#10392, anomalyco#7914, anomalyco#9145, anomalyco#9146, anomalyco#7049, anomalyco#16616, anomalyco#16241 - Plugin subscriber stacking: unsub before re-subscribing in init() - Subagent deallocation: Session.remove() after task completion - SSE stream cleanup: centralized cleanup with done guard (3 endpoints) - Compaction data trimming: clear output/attachments on prune - Process exit cleanup: Instance.disposeAll() with 5s timeout - Serve cmd: graceful shutdown instead of blocking forever - Bash tool: ring buffer with 10MB cap instead of O(n²) concat - LSP index teardown: clear clients/broken/spawning on dispose - LSP open-files cap: evict oldest when >1000 tracked files - Format subscription: store and cleanup unsub handle - Permission/Question clearSession: reject pending on session delete - Session.remove() cleanup chain: FileTime, Permission, Question - ShareNext subscription cleanup: store unsub handles, cleanup on dispose - OAuth transport: close existing before replacing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
347d450 to
274da90
Compare
274da90 to
364633b
Compare
364633b to
895362f
Compare
Keep TUI instances alive during active sessions by wrapping tui() inside Instance.provide() in both thread.ts and attach.ts. This prevents the idle timer from firing while the TUI is running — the ref stays > 0 for the entire session and only drops to 0 when the user exits. Also fix verbose permission ruleset serialization in evaluate() log and add a regression test for the idle-timeout lifecycle invariant.
895362f to
f5ffffe
Compare
Issue for this PR
Fixes #13041
Type of change
What does this PR do?
In serve mode, each unique workspace directory creates an
Instancethat spawns LSP servers, MCP clients, file watchers, and ~26 state entries. These are cached forever and never cleaned up, even after all sessions disconnect — causing unbounded memory growth (2.9GB+ per session as reported in #13041).This PR adds automatic idle-timeout disposal:
Instance idle-timeout disposal (
instance.ts):acquire()/release()tracks activeprovide()calls per directoryOPENCODE_IDLE_TIMEOUTms (default 5 min)provide()calls cancel any pending idle timerInstance.list()returns cached instances with ref counts for observabilityInstance.disposeByDirectory(dir)for API-driven disposalRace condition fix (
state.ts):Configuration (
flag.ts):OPENCODE_IDLE_TIMEOUTenv var (ms, default 300000 = 5 min, set to 0 to disable)API endpoints (
routes/global.ts):GET /global/instances— list cached instances with ref countsPOST /global/instances/dispose— dispose a specific instance by directoryTests (
instance-idle.test.ts):How did you verify your code works?
bun run typecheckpassesChecklist