Auto-clean demux state on pane/window/session close#54
Merged
Conversation
Add documentation to applyWindowClosed clarifying that it does not wrap withEventLock because it performs only DB state operations, similar to applyPaneFocus. State writes serialize at the SQLite layer, unlike pane_closed which must serialize tmux mutations. Add TestApplySessionClosed_EmptyIDStillSweeps to verify that the orphan sweep runs even when session ID is empty.
Extract applyClosedCleanup() from duplicate window_closed and session_closed handlers. Both had identical debug/delete/sweep/return-nil logic, differing only in event name, ID key, and delete function. Add stubSweep(t, fn) test helper using t.Cleanup to auto-restore sweepOrphans. Replaces 4x repeated save/defer pairs in tests, improving readability and reducing cleanup boilerplate. Changes behavior: None. All 822 tests pass.
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.
Context
When a tmux pane is killed, demux automatically clears its tool-state so the TUI doesn't show stale rows. However, killing a window or session left orphaned state rows until a manual
demux gc statesrun. This gap means users could see stale "working" or "error" states for windows/sessions they closed hours ago.This PR extends the auto-cleanup to windows and sessions, cascading to their descendant panes, with a GC-sweep fallback. Panes already covered by the existing
pane_closedhook are now backstopped by the cascade, improving robustness against tmux edge cases.What does this PR do
Database layer
StateDeleteByWindow(windowID)to cascade-delete a window's own state row and all pane rows belonging to that window (identified bywindow_idcolumn).StateDeleteBySessionwhich cascades across all rows for a session (panes, windows, session).Event handlers
sweepOrphanStates(d *db.DB) (deleted int64, skipped bool, err error)fromrunGCStatesinto a reusable helper. The sweep is indirected viavar sweepOrphansfor test stubbing.applyWindowClosedandapplySessionClosedhandlers (best-effort: log errors, always return nil so tmux hooks stay quiet). Each does a targeted cascade delete by hook ID, then sweeps orphans as a catch-all. Lock-free because state-only (serialized at SQLite).window_closedandsession_closedcobra subcommands with--windowand--sessionflags.Tmux integration
window-unlinkedandsession-closedhooks inDesiredHooks(), firingdemux event window_closedanddemux event session_closedrespectively. Both backgrounded (run-shell -b) so never block the tmux command queue.Documentation
withEventLock(state-only, no sticky mutation), and note the linked-window limitation (low-impact, acceptable, self-healing).Out of scope
Manual QA
Prerequisites
1. demux binary is built and hooks are registered.
Expect output: "Registered demux hooks in the live tmux server" or "Updated ~/.tmux.conf".
Verify the hooks were installed:
Expect two lines (exact command strings).
Scenario 1 — Window close clears descendant panes
Scenario 2 — Session close clears all windows and panes
Scenario 3 — Existing pane close still works
after-kill-panehook still works).