Fix worker thread leak on session close in TUI frontends - #734
Closed
JeanStory wants to merge 1 commit into
Closed
Conversation
The per-session agent worker thread was never reclaimed when a session was closed: abort() only set the stop signal without posting a sentinel to the task queue, so run() stayed parked in task_queue.get() forever. - agentmain.py: add shutdown() that aborts and posts a '__shutdown__' sentinel; run() breaks on the sentinel so the worker exits cleanly. - frontends/tuiapp.py: _cmd_close now shuts down and joins the worker. - frontends/tuiapp_v2.py: _shutdown_session joins the worker on close.
Owner
|
TY |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closing a session in the TUI frontends left its background agent worker thread running forever. Over a session's lifetime, repeatedly opening and closing chats caused the process thread count to grow without bound (one leaked
ga-tui-agent-*thread per closed session).Root cause
Each session spins up a background worker thread that runs
GenericAgent.run(), which blocks onself.task_queue.get()waiting for the next task:When a session was closed, the frontend only deleted it from its session dict (
del self.sessions[...]). Nothing ever unblockedtask_queue.get(), so the worker thread stayed parked inget()indefinitely and was never reclaimed.abort()only sets a stop signal for the current task; it does not wake a thread that is idle-waiting for a new one.Fix
Add a
shutdown()method onGenericAgentthat aborts any in-flight task and posts a string sentinel to the queue. The existingrun()loop already breaks out when it receives a non-dict (string) task, so the sentinel makes the worker thread return and terminate cleanly. Frontends callshutdown()on session close and thenjoin()the thread to reclaim it.agentmain.py— newshutdown():frontends/tuiapp.pyandfrontends/tuiapp_v2.py— on close, pop the session, callshutdown(), and join the worker (guarded, best-effort, 5s timeout so the UI never blocks):Testing
/new+/closesessions. Before the fix, each close leaks onega-tui-agent-*thread (count only grows); after the fix, the count returns to baseline as workers are reclaimed.python -m py_compilepasses on all three changed files.Scope / notes
tuiapp.py,tuiapp_v2.py) plus the sharedshutdown()primitive inagentmain.py.shutdown()primitive is generic; other frontends (desktop/ACP bridges) can adopt the same pattern in a follow-up if desired, but they are intentionally out of scope here.join()uses a 5s timeout and is wrapped in a try/except so a slow or wedged worker can never block or crash the UI thread on close.Files changed
agentmain.pyshutdown()(abort + sentinel)frontends/tuiapp.py_cmd_closenow shuts down + joins the workerfrontends/tuiapp_v2.py_cmd_closenow shuts down + joins the worker