Skip to content

Commit f2cedae

Browse files
committed
fix: add safety-net exit for bubbletea renderer deadlock on /exit
When the user types /exit, bubbletea's cursedRenderer can deadlock: its ticker-driven flush goroutine holds a mutex while blocked writing to stdout, and the event loop's final render() call after tea.Quit blocks on the same mutex. p.Run() never returns and the process hangs. Add a safety-net goroutine in cleanupAll() that calls os.Exit(0) after 5 seconds, guaranteeing the process terminates even when bubbletea's renderer is deadlocked. Fixes #2268 Assisted-By: docker-agent
1 parent 990dcd5 commit f2cedae

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

pkg/tui/tui.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,6 +2103,17 @@ func (m *appModel) cleanupAll() {
21032103
for _, ed := range m.editors {
21042104
ed.Cleanup()
21052105
}
2106+
2107+
// Safety net: force-exit if bubbletea's shutdown gets stuck.
2108+
// This can happen when the renderer's flush goroutine blocks on a
2109+
// stdout write (terminal buffer full) while holding the renderer
2110+
// mutex, preventing the event loop from completing the render call
2111+
// that follows tea.Quit.
2112+
go func() {
2113+
time.Sleep(shutdownTimeout)
2114+
slog.Warn("Graceful shutdown timed out, forcing exit")
2115+
exitFunc(0)
2116+
}()
21062117
}
21072118

21082119
// persistedSessionID returns the session-store ID that should be used for

0 commit comments

Comments
 (0)