- Created internal/cleanup package for orphaned process management
- KillOrphanedProcesses(): Finds and kills pg_dump, pg_restore, gzip, pigz
- killProcessGroup(): Kills entire process groups (handles pipelines)
- Pass parent context through all TUI operations (backup/restore inherit cancellation)
- Menu cancel now kills all child processes before exit
- Fixed context chain: menu.ctx → backup/restore operations
- No more zombie processes when user quits TUI mid-operation
Context chain:
- signal.NotifyContext in main.go → menu.ctx
- menu.ctx → backup_exec.ctx, restore_exec.ctx
- Child contexts inherit cancellation via context.WithTimeout(parentCtx)
- All exec.CommandContext use proper parent context
Prevents: Orphaned pg_dump/pg_restore eating CPU/disk after TUI quit
High Priority Fixes:
- Use configurable ClusterTimeoutMinutes for restore (was hardcoded 2 hours)
- Add comment explaining goroutine cleanup in stderr reader (cmd.Run waits)
- Add defer cancel() in cluster backup loop to prevent context leak on panic
Medium Priority Fixes:
- Standardize tick rate to 100ms for both backup and restore (consistent UX)
- Add spinnerFrame field to BackupExecutionModel for incremental updates
- Define package-level spinnerFrames constant to avoid repeated allocation
Low Priority Fixes:
- Add 30-second timeout per database in cluster cleanup loop
- Prevents indefinite hangs when dropping many databases
Optimizations:
- Pre-allocate 512 bytes in View() string builders (reduces allocations)
- Use incremental spinner frame calculation (more efficient than time-based)
- Share spinner frames array across all TUI operations
All changes are backward compatible and maintain existing behavior.
Issue: Interactive cluster restore showed 'Status: Initializing...' throughout
the entire restore process, making it appear stuck even though restore was working.
Root cause:
- Status and phase were set once in NewRestoreExecution()
- Never updated during the restore process
- Only changed to 'Completed' or 'Failed' at the end
- No visual feedback about what stage of restore was running
Solution: Time-based status progression
Added logic in Update() tick handler to change status based on elapsed time:
- 0-2 sec: 'Initializing restore...' / Phase: Starting
- 2-5 sec: Context-aware status:
- If cleanup: 'Cleaning N existing database(s)...' / Phase: Cleanup
- If cluster: 'Extracting cluster archive...' / Phase: Extraction
- If single: 'Preparing restore...' / Phase: Preparation
- 5-10 sec:
- If cluster: 'Restoring global objects...' / Phase: Globals
- If single: 'Restoring database...' / Phase: Restore
- 10+ sec: 'Restoring [cluster] databases...' / Phase: Restore
Benefits:
- User sees the restore is progressing through stages
- Different status messages for cluster vs single database restore
- Shows cleanup phase when enabled
- Spinner + changing status = clear visual feedback
- Better user experience during long-running restores
Note: These are estimated phases since the restore engine runs in silent mode
(no stdout interference with TUI). Actual operation may be faster or slower
than time estimates, but provides much better UX than static 'Initializing'.
Issue: When enabling cluster cleanup (Option C) in interactive restore mode,
the tool tried to connect to the database to drop existing databases. This
was confusing because:
- Cluster restore itself doesn't use database connections
- It uses CLI tools (psql, pg_restore) directly
- Connection errors were misleading to users
Solution: Changed cleanup to use psql command directly (dropDatabaseCLI)
- Matches how cluster restore works (CLI tools, not connections)
- No confusing connection errors
- Cleaner, more consistent behavior
- Uses postgres maintenance DB for DROP DATABASE commands
Files changed:
- internal/tui/restore_exec.go: Added dropDatabaseCLI() helper function
- Removed dbClient.Connect() requirement for cleanup
- Cleanup now works exactly like cluster restore operations
- Auto-detects existing user databases before cluster restore
- Shows count and list (first 5) in preview screen
- Toggle option 'c' to enable cluster cleanup
- Drops all user databases before restore when enabled
- Works for PostgreSQL, MySQL, MariaDB
- Safety warning with database count
- Implements practical disaster recovery workflow