Optimize: Fix high/medium/low priority issues and apply optimizations

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.
This commit is contained in:
2025-11-12 11:37:02 +00:00
parent 2ad9032b19
commit 2019591b5b
3 changed files with 25 additions and 8 deletions

View File

@@ -399,8 +399,9 @@ func (e *Engine) BackupCluster(ctx context.Context) error {
// Use a context with timeout for each database to prevent hangs
// Use longer timeout for huge databases (2 hours per database)
dbCtx, cancel := context.WithTimeout(ctx, 2*time.Hour)
defer cancel() // Ensure cancel is called even if executeCommand panics
err := e.executeCommand(dbCtx, cmd, dumpFile)
cancel()
cancel() // Also call immediately for early cleanup
if err != nil {
e.log.Warn("Failed to backup database", "database", dbName, "error", err)
@@ -786,6 +787,7 @@ regularTar:
cmd := exec.CommandContext(ctx, compressCmd, compressArgs...)
// Stream stderr to avoid memory issues
// Use io.Copy to ensure goroutine completes when pipe closes
stderr, err := cmd.StderrPipe()
if err == nil {
go func() {
@@ -796,12 +798,14 @@ regularTar:
e.log.Debug("Archive creation", "output", line)
}
}
// Scanner will exit when stderr pipe closes after cmd.Wait()
}()
}
if err := cmd.Run(); err != nil {
return fmt.Errorf("tar failed: %w", err)
}
// cmd.Run() calls Wait() which closes stderr pipe, terminating the goroutine
return nil
}