refactor: 消除集群执行服务冗余逻辑 + 修复节点状态滞后缺陷 (#74)

抽取备份/恢复/验证/复制四服务的复制粘贴逻辑到 execution_helpers.go(净减约 250 行);节点状态改为按 LastSeen 实时推导,消除过期 online 误判;Agent systemd 单元补齐 LimitNOFILE 与单机端一致。go build/test 全绿。
This commit is contained in:
Wu Qing
2026-05-26 14:12:39 +08:00
committed by GitHub
parent e4c52fd8f4
commit 0f30e7bf52
10 changed files with 317 additions and 323 deletions
@@ -15,8 +15,6 @@ import (
"backupx/server/internal/repository"
"backupx/server/internal/storage"
"backupx/server/internal/storage/codec"
"backupx/server/pkg/compress"
backupcrypto "backupx/server/pkg/crypto"
)
// VerificationService 管理备份验证(恢复演练)记录生命周期。
@@ -92,11 +90,11 @@ func (v *VerificationEventNotifier) NotifyVerificationResult(ctx context.Context
title := "BackupX 备份验证失败"
body := fmt.Sprintf("任务:%s\n验证记录:#%d\n错误:%s", taskName, record.ID, record.ErrorMessage)
fields := map[string]any{
"taskId": record.TaskID,
"taskName": taskName,
"verifyId": record.ID,
"taskId": record.TaskID,
"taskName": taskName,
"verifyId": record.ID,
"backupRecordId": record.BackupRecordID,
"error": record.ErrorMessage,
"error": record.ErrorMessage,
}
return v.dispatcher.DispatchEvent(ctx, model.NotificationEventVerifyFailed, title, body, fields)
}
@@ -243,23 +241,8 @@ func (s *VerificationService) Start(ctx context.Context, backupRecordID uint, mo
// validateClusterAccessible 复刻 BackupExecutionService 的跨节点 local_disk 保护。
// 避免 Master 端在错误机器下载/校验到假数据。
func (s *VerificationService) validateClusterAccessible(ctx context.Context, record *model.BackupRecord) error {
if record == nil || record.NodeID == 0 || s.nodeRepo == nil {
return nil
}
node, err := s.nodeRepo.FindByID(ctx, record.NodeID)
if err != nil || node == nil || node.IsLocal {
return nil
}
target, err := s.targets.FindByID(ctx, record.StorageTargetID)
if err != nil || target == nil {
return nil
}
if strings.EqualFold(target.Type, "local_disk") {
return apperror.BadRequest("VERIFY_CROSS_NODE_LOCAL_DISK",
fmt.Sprintf("备份位于节点 %s 的本地磁盘(local_disk),Master 无法跨节点验证。", node.Name),
nil)
}
return nil
return validateCrossNodeLocalDisk(ctx, s.nodeRepo, s.targets, record,
"VERIFY_CROSS_NODE_LOCAL_DISK", "验证")
}
// executeLocally 异步执行验证:下载 → 解密 → 解压 → 按类型校验。
@@ -358,24 +341,7 @@ func (s *VerificationService) executeLocally(ctx context.Context, verID uint, ta
// prepareArtifact 按后缀解密/解压,返回可读路径。
func (s *VerificationService) prepareArtifact(artifactPath string, logger *backup.ExecutionLogger) (string, error) {
current := artifactPath
if strings.HasSuffix(strings.ToLower(current), ".enc") {
logger.Infof("检测到加密后缀,开始解密")
decrypted, err := backupcrypto.DecryptFile(s.cipher.Key(), current)
if err != nil {
return "", err
}
current = decrypted
}
if strings.HasSuffix(strings.ToLower(current), ".gz") {
logger.Infof("检测到 gzip,解压")
decompressed, err := compress.GunzipFile(current)
if err != nil {
return "", err
}
current = decompressed
}
return current, nil
return prepareBackupArtifact(s.cipher, artifactPath, logger)
}
// verifyByType 按任务类型分派到对应 Verify* 策略。