mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 23:40:24 +08:00
213 lines
5.9 KiB
Go
213 lines
5.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"mayfly-go/internal/db/domain/entity"
|
|
"mayfly-go/internal/db/domain/repository"
|
|
"mayfly-go/internal/db/domain/service"
|
|
"mayfly-go/pkg/model"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
var _ service.DbBackupSvc = (*DbBackupSvcImpl)(nil)
|
|
|
|
type DbBackupSvcImpl struct {
|
|
repo repository.DbBackup
|
|
instanceRepo repository.Instance
|
|
scheduler *Scheduler[*entity.DbBackup]
|
|
binlogSvc service.DbBinlogSvc
|
|
}
|
|
|
|
func NewIncUUID() (uuid.UUID, error) {
|
|
var uid uuid.UUID
|
|
now, seq, err := uuid.GetTime()
|
|
if err != nil {
|
|
return uid, err
|
|
}
|
|
timeHi := uint32((now >> 28) & 0xffffffff)
|
|
timeMid := uint16((now >> 12) & 0xffff)
|
|
timeLow := uint16(now & 0x0fff)
|
|
timeLow |= 0x1000 // Version 1
|
|
|
|
binary.BigEndian.PutUint32(uid[0:], timeHi)
|
|
binary.BigEndian.PutUint16(uid[4:], timeMid)
|
|
binary.BigEndian.PutUint16(uid[6:], timeLow)
|
|
binary.BigEndian.PutUint16(uid[8:], seq)
|
|
|
|
copy(uid[10:], uuid.NodeID())
|
|
|
|
return uid, nil
|
|
}
|
|
|
|
func withRunBackupTask(repositories *repository.Repositories, binlogSvc service.DbBinlogSvc) SchedulerOption[*entity.DbBackup] {
|
|
return func(scheduler *Scheduler[*entity.DbBackup]) {
|
|
scheduler.RunTask = func(ctx context.Context, task *entity.DbBackup) error {
|
|
instance := new(entity.DbInstance)
|
|
if err := repositories.Instance.GetById(instance, task.DbInstanceId); err != nil {
|
|
return err
|
|
}
|
|
instance.PwdDecrypt()
|
|
id, err := NewIncUUID()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
history := &entity.DbBackupHistory{
|
|
Uuid: id.String(),
|
|
DbBackupId: task.Id,
|
|
DbInstanceId: task.DbInstanceId,
|
|
DbName: task.DbName,
|
|
}
|
|
binlogInfo, err := NewDbInstanceSvc(instance, repositories).Backup(ctx, history)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
now := time.Now()
|
|
name := task.Name
|
|
if len(name) == 0 {
|
|
name = task.DbName
|
|
}
|
|
history.Name = fmt.Sprintf("%s[%s]", name, now.Format(time.DateTime))
|
|
history.CreateTime = now
|
|
history.BinlogFileName = binlogInfo.FileName
|
|
history.BinlogSequence = binlogInfo.Sequence
|
|
history.BinlogPosition = binlogInfo.Position
|
|
|
|
if err := repositories.BackupHistory.Insert(ctx, history); err != nil {
|
|
return err
|
|
}
|
|
if err := binlogSvc.AddTaskIfNotExists(ctx, entity.NewDbBinlog(history)); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
var (
|
|
backupResult = map[entity.TaskStatus]string{
|
|
entity.TaskDelay: "等待备份数据库",
|
|
entity.TaskReady: "准备备份数据库",
|
|
entity.TaskReserved: "数据库备份中",
|
|
entity.TaskSuccess: "数据库备份成功",
|
|
entity.TaskFailed: "数据库备份失败",
|
|
}
|
|
)
|
|
|
|
func withUpdateBackupStatus(repositories *repository.Repositories) SchedulerOption[*entity.DbBackup] {
|
|
return func(scheduler *Scheduler[*entity.DbBackup]) {
|
|
scheduler.UpdateTaskStatus = func(ctx context.Context, status entity.TaskStatus, lastErr error, task *entity.DbBackup) error {
|
|
task.Finished = !task.Repeated && status == entity.TaskSuccess
|
|
task.LastStatus = status
|
|
var result = backupResult[status]
|
|
if lastErr != nil {
|
|
result = fmt.Sprintf("%v: %v", backupResult[status], lastErr)
|
|
}
|
|
task.LastResult = result
|
|
task.LastTime = time.Now()
|
|
return repositories.Backup.UpdateTaskStatus(ctx, task)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewDbBackupSvc(repositories *repository.Repositories, binlogSvc service.DbBinlogSvc) (service.DbBackupSvc, error) {
|
|
scheduler, err := NewScheduler[*entity.DbBackup](
|
|
withRunBackupTask(repositories, binlogSvc),
|
|
withUpdateBackupStatus(repositories))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
svc := &DbBackupSvcImpl{
|
|
repo: repositories.Backup,
|
|
instanceRepo: repositories.Instance,
|
|
scheduler: scheduler,
|
|
binlogSvc: binlogSvc,
|
|
}
|
|
err = svc.loadTasks(context.Background())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return svc, nil
|
|
}
|
|
|
|
func (svc *DbBackupSvcImpl) loadTasks(ctx context.Context) error {
|
|
tasks := make([]*entity.DbBackup, 0, 64)
|
|
cond := map[string]any{
|
|
"Enabled": true,
|
|
"Finished": false,
|
|
}
|
|
if err := svc.repo.ListByCond(cond, &tasks); err != nil {
|
|
return err
|
|
}
|
|
for _, task := range tasks {
|
|
svc.scheduler.PushTask(ctx, task)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (svc *DbBackupSvcImpl) AddTask(ctx context.Context, tasks ...*entity.DbBackup) error {
|
|
for _, task := range tasks {
|
|
if err := svc.repo.AddTask(ctx, task); err != nil {
|
|
return err
|
|
}
|
|
svc.scheduler.PushTask(ctx, task)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (svc *DbBackupSvcImpl) UpdateTask(ctx context.Context, task *entity.DbBackup) error {
|
|
if err := svc.repo.UpdateById(ctx, task); err != nil {
|
|
return err
|
|
}
|
|
svc.scheduler.UpdateTask(ctx, task)
|
|
return nil
|
|
}
|
|
|
|
func (svc *DbBackupSvcImpl) DeleteTask(ctx context.Context, taskId uint64) error {
|
|
// todo: 删除数据库备份历史文件
|
|
task := new(entity.DbBackup)
|
|
if err := svc.repo.GetById(task, taskId); err != nil {
|
|
return err
|
|
}
|
|
if err := svc.binlogSvc.DeleteTask(ctx, task.DbInstanceId); err != nil {
|
|
return err
|
|
}
|
|
if err := svc.repo.DeleteById(ctx, taskId); err != nil {
|
|
return err
|
|
}
|
|
svc.scheduler.RemoveTask(taskId)
|
|
return nil
|
|
}
|
|
|
|
func (svc *DbBackupSvcImpl) EnableTask(ctx context.Context, taskId uint64) error {
|
|
if err := svc.repo.UpdateEnabled(ctx, taskId, true); err != nil {
|
|
return err
|
|
}
|
|
task := new(entity.DbBackup)
|
|
if err := svc.repo.GetById(task, taskId); err != nil {
|
|
return err
|
|
}
|
|
svc.scheduler.UpdateTask(ctx, task)
|
|
return nil
|
|
}
|
|
|
|
func (svc *DbBackupSvcImpl) DisableTask(ctx context.Context, taskId uint64) error {
|
|
if err := svc.repo.UpdateEnabled(ctx, taskId, false); err != nil {
|
|
return err
|
|
}
|
|
task := new(entity.DbBackup)
|
|
if err := svc.repo.GetById(task, taskId); err != nil {
|
|
return err
|
|
}
|
|
svc.scheduler.RemoveTask(taskId)
|
|
return nil
|
|
}
|
|
|
|
// GetPageList 分页获取数据库备份任务
|
|
func (svc *DbBackupSvcImpl) GetPageList(condition *entity.DbBackupQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
|
return svc.repo.GetDbBackupList(condition, pageParam, toEntity, orderBy...)
|
|
}
|