Orphaned Gate.serve() REPLs are never reaped — multi-GB leak under headless server #51
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
kahliburke/Kaimon.jl#51
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Gate worker processes started via
Gate.serve()register a session with the server but are never terminated when abandoned. Over many editor/agent sessions and projects they accumulate as idle multi-GB Julia processes. On my machine I found four orphaned serve REPLs (one project had two) plus a leaked/tmp/kaimon_test_runnerchild — ~20 GB of RSS held by processes that had been idle for hours to over a day.Root cause
close_session!(src/session.jl) only setssession.state = CLOSED— it never signals the OS process, so the worker keeps running._reap_stale_sessions!insrc/tui/view.jl) is driven from the TUI render loop and operates on MCP client sessions (STANDALONE_SESSIONS), not on the gate worker processes (ConnectionManagerREPLConnections with.pid). A headless-m Kaimonserver never ticks it.last_seen: health pings flow through_req_send_recv, which refresheslast_seenevery cycle. There was no activity timestamp independent of pings.Net effect: nothing ever sends a signal to an abandoned gate, even though
REPLConnectionalready carries everything needed (pid,project_path,status,allow_restart).Proposed fix
Branch:
1-Bart-1:fix/reap-orphaned-serve-repls· commit7a8ec78Reap idle gates from the
ConnectionManagerhealth loop (runs in both TUI and headless modes):last_tool_calltimestamp, stamped via_note_tool_activity!at every real tool call / eval._should_reap_idle_gateflags a:connected, restartable, non-paused gate idle beyond a threshold (evaluating / stalled / debug-paused /allow_restart=falseextension gates are skipped).send_shutdown!and pruned through the existing removal path.gate_idle_reap_secondspreference, default0(disabled) so behaviour is opt-in.Happy to open this as a PR.
@1-Bart-1 Thank you for the bug report, I will take a look. I am working on a 2.0.0 release and I may have fixed a related issue but I will make sure to incorporate any additional fixes in your branch.
Thanks for the detailed report and the branch, @1-Bart-1. I looked into this for the 2.0 release.
When I instrumented it, Kaimon-spawned sessions (
start_sessionand agent sessions) don't actually orphan. I tested both exit paths on a headless server:stop_all_sessions!.kill -9of the server: the spawned gate still dies — it's a PTY child, so it getsSIGHUPwhen the parent goes away.A process check after each confirmed no spawned gate survived. So the persistent multi-GB
Gate.serve()REPLs are user/editor-started gates — separate processes Kaimon connects to but doesn't own.That persistence is intended. Sessions are meant to survive a Kaimon restart so REPL state isn't lost; a restarted Kaimon (or an agent) finds them again via socket discovery /
pingand reuses them. So Kaimon doesn't force-kill gates it didn't spawn — one might hold work you still want. An opt-in idle cleanup scoped to spawned sessions only is something I'd consider as a future feature.One item in your report is a real leak and I'll fix it: the
/tmp/kaimon_test_runnerchild. The test-runner subprocess isn't tied into shutdown and can orphan if a run hangs or Kaimon exits mid-run, and its temp script isn't cleaned up. I'll track in-flight runs, reap them on shutdown, and remove the temp file.Your report also prompted a wider change: the maintenance you noted was TUI-only (stale-session reaping, extension/session monitoring) now runs headless too in 2.0, along with headless analytics-DB init and periodic indexing.
One question: were the four orphaned serve REPLs started by
start_session/ the VS Code extension, or by hand (julia> Gate.serve())? I'll revisit this after the 2.0 release — if you can share more detail on how those REPLs were started and your setup, it'll help me track down whether there's a real issue in Kaimon's path.Thanks again.
I start the REPLs by hand (julia> Gate.serve()). Then using claude code to connect to the MCP server.
Thanks for looking into this, and explaining this. Makes sense.
Following up now that 2.0 is further along, and given your confirmation that all four orphaned REPLs were hand-started (
julia> Gate.serve()) rather than viastart_session/ the VS Code extension.Decision: not taking the idle-reaper approach from the branch as-is.
The proposed fix reaps idle gates from the
ConnectionManagerhealth loop based on agate_idle_reap_secondsthreshold. The problem is it can't distinguish "abandoned" from "idle but wanted" for gates Kaimon doesn't own. A hand-startedGate.serve()REPL is a process Kaimon merely connects to — it may hold expensive in-memory state (loaded data, a half-finished computation) you want to keep across a Kaimon restart. That cross-restart persistence is intentional: a restarted Kaimon (or a fresh agent) rediscovers these gates via socket discovery /pingand reuses them. Time-based force-reaping would kill exactly the long-lived REPLs people deliberately keep running.What did change for 2.0:
start_session, agent sessions) are confirmed not to orphan — reaped bystop_all_sessions!on clean stop, and they die onkill -9of the server too (PTY children getSIGHUP).So for the user-started case there isn't a Kaimon-side leak to fix per se — but I don't want to just close this, because the underlying ask ("don't let abandoned hand-started REPLs pile up") is real. Before adding anything I'd want to investigate:
last_seen, so idleness can't be measured from it today. The branch'slast_tool_callidea is reasonable here.Keeping this open as an investigation item. Thanks again @1-Bart-1 — the report and branch were a useful prompt even though the fix will likely land differently.
@1-Bart-1 Please check out 2.0 which has shipped, there is more agent/session affinity which may help your use cases. Otherwise please open an issue against 2.0.