Add repair worker

This commit is contained in:
Mukhtar Akere
2025-01-09 19:44:38 +01:00
parent 28e5342c66
commit 03c9657945
19 changed files with 783 additions and 235 deletions

72
pkg/repair/repair.go Normal file
View File

@@ -0,0 +1,72 @@
package repair
import (
"context"
"goBlack/common"
"goBlack/pkg/arr"
"log"
"os"
"os/signal"
"strings"
"syscall"
"time"
)
func Start(ctx context.Context, config *common.Config, arrs *arr.Storage) error {
ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
logger := common.NewLogger("Repair", os.Stdout)
defer stop()
duration, err := parseSchedule(config.Repair.Interval)
if err != nil {
log.Fatalf("Failed to parse schedule: %v", err)
}
if config.Repair.RunOnStart {
logger.Printf("Running initial repair")
if err := repair(arrs); err != nil {
log.Printf("Error during initial repair: %v", err)
return err
}
}
ticker := time.NewTicker(duration)
defer ticker.Stop()
if strings.Contains(config.Repair.Interval, ":") {
logger.Printf("Starting repair worker, scheduled daily at %s", config.Repair.Interval)
} else {
logger.Printf("Starting repair worker with %v interval", duration)
}
for {
select {
case <-ctx.Done():
logger.Println("Repair worker stopped")
return nil
case t := <-ticker.C:
logger.Printf("Running repair at %v", t.Format("15:04:05"))
if err := repair(arrs); err != nil {
logger.Printf("Error during repair: %v", err)
return err
}
// If using time-of-day schedule, reset the ticker for next day
if strings.Contains(config.Repair.Interval, ":") {
nextDuration, err := parseSchedule(config.Repair.Interval)
if err != nil {
logger.Printf("Error calculating next schedule: %v", err)
return err
}
ticker.Reset(nextDuration)
}
}
}
}
func repair(arrs *arr.Storage) error {
for _, a := range arrs.GetAll() {
go a.Repair("")
}
return nil
}

70
pkg/repair/utils.go Normal file
View File

@@ -0,0 +1,70 @@
package repair
import (
"fmt"
"strconv"
"strings"
"time"
)
func parseSchedule(schedule string) (time.Duration, error) {
if schedule == "" {
return time.Hour, nil // default 60m
}
// Check if it's a time-of-day format (HH:MM)
if strings.Contains(schedule, ":") {
return parseTimeOfDay(schedule)
}
// Otherwise treat as duration interval
return parseDurationInterval(schedule)
}
func parseTimeOfDay(schedule string) (time.Duration, error) {
now := time.Now()
scheduledTime, err := time.Parse("15:04", schedule)
if err != nil {
return 0, fmt.Errorf("invalid time format: %s. Use HH:MM in 24-hour format", schedule)
}
// Convert scheduled time to today
scheduleToday := time.Date(
now.Year(), now.Month(), now.Day(),
scheduledTime.Hour(), scheduledTime.Minute(), 0, 0,
now.Location(),
)
if scheduleToday.Before(now) {
scheduleToday = scheduleToday.Add(24 * time.Hour)
}
return scheduleToday.Sub(now), nil
}
func parseDurationInterval(interval string) (time.Duration, error) {
if len(interval) < 2 {
return 0, fmt.Errorf("invalid interval format: %s", interval)
}
numStr := interval[:len(interval)-1]
unit := interval[len(interval)-1]
num, err := strconv.Atoi(numStr)
if err != nil {
return 0, fmt.Errorf("invalid number in interval: %s", numStr)
}
switch unit {
case 'm':
return time.Duration(num) * time.Minute, nil
case 'h':
return time.Duration(num) * time.Hour, nil
case 'd':
return time.Duration(num) * 24 * time.Hour, nil
case 's':
return time.Duration(num) * time.Second, nil
default:
return 0, fmt.Errorf("invalid unit in interval: %c", unit)
}
}