cmd/clickhouse-backup/main.go (90 lines of code) (raw):
package main
import (
"context"
"fmt"
"log/slog"
"os"
"time"
"github.com/Altinity/clickhouse-backup/pkg/backup"
"github.com/Altinity/clickhouse-backup/pkg/status"
clickhousebackup "github.com/JetBrains/ij-perf-report-aggregator/pkg/clickhouse-backup"
"github.com/JetBrains/ij-perf-report-aggregator/pkg/util"
"github.com/nats-io/nats.go"
"go.deanishe.net/env"
)
func main() {
err := start("nats://" + env.Get("NATS", "nats:4222"))
if err != nil {
slog.Error("cannot start backup", "err", err)
os.Exit(1)
}
}
func start(natsUrl string) error {
taskContext, cancel := util.CreateCommandContext()
defer cancel()
if os.Getenv("KUBERNETES_SERVICE_HOST") == "" {
clickhousebackup.SetS3EnvForLocalRun(taskContext)
}
backuper := clickhousebackup.CreateBackuper()
if env.GetBool("DO_BACKUP") {
err := executeBackup(taskContext, backuper)
return err
}
slog.Info("started", "nats", natsUrl)
nc, err := nats.Connect(natsUrl)
if err != nil {
return fmt.Errorf("cannot connect to nats: %w", err)
}
sub, err := nc.SubscribeSync("db.backup")
if err != nil {
return fmt.Errorf("cannot subscribe to db.backup: %w", err)
}
lastBackupTime := time.Time{}
for taskContext.Err() == nil {
_, err = sub.NextMsgWithContext(taskContext)
if err != nil {
contextError := taskContext.Err()
if contextError != nil {
slog.Info("cancelled", "reason", contextError)
return nil
}
return fmt.Errorf("cannot receive message: %w", err)
}
if taskContext.Err() != nil {
return nil
}
if time.Since(lastBackupTime) < 24*time.Hour {
// do not create backups too often
slog.Info("backup request skipped", "reason", "time threshold", "lastBackupTime", lastBackupTime)
continue
}
slog.Info("backup requested")
err = executeBackup(taskContext, backuper)
if err != nil {
slog.Error("cannot backup", "error", err)
} else {
lastBackupTime = time.Now()
}
}
return nil
}
func executeBackup(taskContext context.Context, backuper *backup.Backuper) error {
backupName := backup.NewBackupName()
logger := slog.With("backup", backupName)
err := backuper.CreateBackup(backupName, "", nil, false, false, false, false, "unknown", status.NotFromAPI)
if err != nil {
return fmt.Errorf("cannot create backup: %w", err)
}
if taskContext.Err() != nil {
return nil
}
logger.Info("upload")
err = backuper.Upload(backupName, "", "", "", nil, false, false, status.NotFromAPI)
if err != nil {
return err
}
if taskContext.Err() != nil {
return nil
}
logger.Info("uploaded")
return nil
}