polish: Week 2 improvements - error messages, progress, performance

## Error Message Improvements (Phase 1)
-  Cluster backup: Added database type context to error messages
-  Rate limiting: Show specific host and wait time in errors
-  Connection failures: Added troubleshooting steps (3-point checklist)
-  Encryption errors: Include backup location in failure messages
-  Archive not found: Suggest cloud:// URI for remote backups
-  Decryption: Hint about wrong key verification
-  Backup directory: Include permission hints and --backup-dir suggestion
-  Backup execution: Show database name and diagnostic checklist
-  Incremental: Better base backup path guidance
-  File verification: Indicate silent command failure possibility

## Progress Indicator Enhancements (Phase 2)
-  ETA calculations: Real-time estimation based on transfer speed
-  Speed formatting: formatSpeed() helper (B/KB/MB/GB per second)
-  Byte formatting: formatBytes() with proper unit scaling
-  Duration display: Improved to show Xm Ys format vs decimal
-  Progress updates: Show [%] bytes/total (speed, ETA: time) format

## Performance Optimization (Phase 3)
-  Buffer sizes: Increased stderr read buffers from 4KB to 64KB
-  Scanner buffers: 64KB initial, 1MB max for command output
-  I/O throughput: Better buffer alignment for streaming operations

## Code Cleanup (Phase 4)
-  TODO comments: Converted to descriptive comments
-  Method calls: Fixed GetDatabaseType() -> DisplayDatabaseType()
-  Build verification: All changes compile successfully

## Summary
Time: ~1.5h (2-4h estimated)
Changed: 4 files (cmd/backup_impl.go, cmd/restore.go, internal/backup/engine.go, internal/progress/detailed.go)
Impact: Better UX, clearer errors, faster I/O, cleaner code
This commit is contained in:
2025-11-26 10:30:29 +00:00
parent 2039a22d95
commit 3ef57bb2f5
8 changed files with 115 additions and 47 deletions

View File

@@ -146,9 +146,10 @@ func (e *Engine) BackupSingle(ctx context.Context, databaseName string) error {
e.cfg.BackupDir = validBackupDir
if err := os.MkdirAll(e.cfg.BackupDir, 0755); err != nil {
prepStep.Fail(fmt.Errorf("failed to create backup directory: %w", err))
tracker.Fail(fmt.Errorf("failed to create backup directory: %w", err))
return fmt.Errorf("failed to create backup directory: %w", err)
err = fmt.Errorf("failed to create backup directory %s. Check write permissions or use --backup-dir to specify writable location: %w", e.cfg.BackupDir, err)
prepStep.Fail(err)
tracker.Fail(err)
return err
}
prepStep.Complete("Backup directory prepared")
tracker.UpdateProgress(10, "Backup directory prepared")
@@ -186,9 +187,10 @@ func (e *Engine) BackupSingle(ctx context.Context, databaseName string) error {
tracker.UpdateProgress(40, "Starting database backup...")
if err := e.executeCommandWithProgress(ctx, cmd, outputFile, tracker); err != nil {
execStep.Fail(fmt.Errorf("backup execution failed: %w", err))
tracker.Fail(fmt.Errorf("backup failed: %w", err))
return fmt.Errorf("backup failed: %w", err)
err = fmt.Errorf("backup failed for %s: %w. Check database connectivity and disk space", databaseName, err)
execStep.Fail(err)
tracker.Fail(err)
return err
}
execStep.Complete("Database backup completed")
tracker.UpdateProgress(80, "Database backup completed")
@@ -196,9 +198,10 @@ func (e *Engine) BackupSingle(ctx context.Context, databaseName string) error {
// Verify backup file
verifyStep := tracker.AddStep("verify", "Verifying backup file")
if info, err := os.Stat(outputFile); err != nil {
verifyStep.Fail(fmt.Errorf("backup file not created: %w", err))
tracker.Fail(fmt.Errorf("backup file not created: %w", err))
return fmt.Errorf("backup file not created: %w", err)
err = fmt.Errorf("backup file not created at %s. Backup command may have failed silently: %w", outputFile, err)
verifyStep.Fail(err)
tracker.Fail(err)
return err
} else {
size := formatBytes(info.Size())
tracker.SetDetails("file_size", size)
@@ -611,6 +614,7 @@ func (e *Engine) monitorCommandProgress(stderr io.ReadCloser, tracker *progress.
defer stderr.Close()
scanner := bufio.NewScanner(stderr)
scanner.Buffer(make([]byte, 64*1024), 1024*1024) // 64KB initial, 1MB max for performance
progressBase := 40 // Start from 40% since command preparation is done
progressIncrement := 0