Files
apocapoc-api/internal/infrastructure/backup/retention.go
T
david e9e7e9dbac Add automated backup system with SQLite VACUUM
- Implement backup package with SQLite VACUUM INTO for safe backups
- Add scheduler with configurable interval (default: 24h)
- Add retention policy with automatic cleanup (default: 7 days)
- Add optional gzip compression (~10x size reduction)
- Add comprehensive tests for backup creation and cleanup
- Integrate backup scheduler in main.go with graceful shutdown
- Add backup configuration variables (BACKUP_ENABLED, BACKUP_INTERVAL, BACKUP_RETENTION_DAYS, BACKUP_PATH, BACKUP_COMPRESS)
- Backups run automatically in background goroutine
- Coverage: backup package 52.7%
2025-12-05 00:17:37 +01:00

81 lines
1.4 KiB
Go

package backup
import (
"os"
"path/filepath"
"strings"
"time"
"apocapoc-api/internal/infrastructure/logger"
)
func CleanOldBackups(config Config) error {
if !config.Enabled {
return nil
}
if config.RetentionDays <= 0 {
return nil
}
cutoffTime := time.Now().AddDate(0, 0, -config.RetentionDays)
files, err := os.ReadDir(config.Path)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
deletedCount := 0
for _, file := range files {
if file.IsDir() {
continue
}
if !strings.HasPrefix(file.Name(), "apocapoc_") {
continue
}
if !strings.HasSuffix(file.Name(), ".db") && !strings.HasSuffix(file.Name(), ".db.gz") {
continue
}
filePath := filepath.Join(config.Path, file.Name())
info, err := os.Stat(filePath)
if err != nil {
logger.Warn().
Err(err).
Str("file", filePath).
Msg("Failed to stat backup file")
continue
}
if info.ModTime().Before(cutoffTime) {
if err := os.Remove(filePath); err != nil {
logger.Warn().
Err(err).
Str("file", filePath).
Msg("Failed to delete old backup")
continue
}
logger.Info().
Str("file", file.Name()).
Time("mod_time", info.ModTime()).
Msg("Deleted old backup")
deletedCount++
}
}
if deletedCount > 0 {
logger.Info().
Int("deleted_count", deletedCount).
Int("retention_days", config.RetentionDays).
Msg("Backup cleanup completed")
}
return nil
}