修复空计划不会反复执行
This commit is contained in:
@@ -246,48 +246,7 @@ func (s *Scheduler) processTask(claimedLog *models.TaskExecutionLog) {
|
|||||||
// 如果此计划执行中,未完成的任务只剩下当前这一个(因为当前任务的状态此时在数据库中仍为 'started'),
|
// 如果此计划执行中,未完成的任务只剩下当前这一个(因为当前任务的状态此时在数据库中仍为 'started'),
|
||||||
// 则认为整个计划已完成。
|
// 则认为整个计划已完成。
|
||||||
if incompleteCount == 1 {
|
if incompleteCount == 1 {
|
||||||
s.logger.Infof("计划执行 %d 的所有任务已完成,开始处理计划完成逻辑...", claimedLog.PlanExecutionLogID)
|
s.handlePlanCompletion(claimedLog.PlanExecutionLogID)
|
||||||
|
|
||||||
// 通过 PlanExecutionLog 反查正确的顶层 PlanID
|
|
||||||
planExecutionLog, err := s.executionLogRepo.FindPlanExecutionLogByID(claimedLog.PlanExecutionLogID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Errorf("获取计划执行日志 %d 失败: %v", claimedLog.PlanExecutionLogID, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
planID := planExecutionLog.PlanID // 这才是正确的顶层计划ID
|
|
||||||
|
|
||||||
// 获取计划的最新数据,这里我们只需要基本信息来判断执行类型和次数
|
|
||||||
plan, err := s.planRepo.GetBasicPlanByID(planID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Errorf("获取计划 %d 的基本信息失败: %v", planID, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在内存中计算新的计数值和状态
|
|
||||||
newExecuteCount := plan.ExecuteCount + 1
|
|
||||||
newStatus := plan.Status // 默认为当前状态
|
|
||||||
|
|
||||||
// 如果是自动计划且达到执行次数上限,或计划是手动类型,则更新计划状态为已停止
|
|
||||||
if (plan.ExecutionType == models.PlanExecutionTypeAutomatic && plan.ExecuteNum > 0 && newExecuteCount >= plan.ExecuteNum) || plan.ExecutionType == models.PlanExecutionTypeManual {
|
|
||||||
newStatus = models.PlanStatusStopeed
|
|
||||||
s.logger.Infof("计划 %d 已完成执行,状态更新为 '执行完毕'。", planID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用新的、专门的方法来原子性地更新计数值和状态
|
|
||||||
if err := s.planRepo.UpdatePlanStateAfterExecution(planID, newExecuteCount, newStatus); err != nil {
|
|
||||||
s.logger.Errorf("更新计划 %d 的执行后状态失败: %v", planID, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新计划执行日志状态为完成
|
|
||||||
if err := s.executionLogRepo.UpdatePlanExecutionLogStatus(claimedLog.PlanExecutionLogID, models.ExecutionStatusCompleted); err != nil {
|
|
||||||
s.logger.Errorf("更新计划执行日志 %d 状态为 '完成' 失败: %v", claimedLog.PlanExecutionLogID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用共享的 Manager 来处理触发器更新逻辑
|
|
||||||
if err := s.analysisPlanTaskManager.CreateOrUpdateTrigger(planID); err != nil {
|
|
||||||
s.logger.Errorf("为计划 %d 创建/更新触发器失败: %v", planID, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,6 +346,13 @@ func (s *Scheduler) analysisPlan(claimedLog *models.TaskExecutionLog) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 处理空计划的边缘情况 ---
|
||||||
|
// 如果一个计划被解析后,发现其任务列表为空,
|
||||||
|
// 那么它实际上已经“执行”完毕了,我们需要在这里手动为它创建下一次的触发器。
|
||||||
|
if len(tasks) == 0 {
|
||||||
|
s.handlePlanCompletion(planLog.ID)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,3 +395,49 @@ func (s *Scheduler) handlePlanTermination(planLogID uint, reason string) {
|
|||||||
s.logger.Errorf("更新计划 %d 状态为 '失败' 时出错: %v", planLog.PlanID, err)
|
s.logger.Errorf("更新计划 %d 状态为 '失败' 时出错: %v", planLog.PlanID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handlePlanCompletion 集中处理计划成功完成后的所有逻辑
|
||||||
|
func (s *Scheduler) handlePlanCompletion(planLogID uint) {
|
||||||
|
s.logger.Infof("计划执行 %d 的所有任务已完成,开始处理计划完成逻辑...", planLogID)
|
||||||
|
|
||||||
|
// 1. 通过 PlanExecutionLog 反查正确的顶层 PlanID
|
||||||
|
planExecutionLog, err := s.executionLogRepo.FindPlanExecutionLogByID(planLogID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Errorf("获取计划执行日志 %d 失败: %v", planLogID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
topLevelPlanID := planExecutionLog.PlanID // 这才是正确的顶层计划ID
|
||||||
|
|
||||||
|
// 2. 获取计划的最新数据,这里我们只需要基本信息来判断执行类型和次数
|
||||||
|
plan, err := s.planRepo.GetBasicPlanByID(topLevelPlanID)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Errorf("获取计划 %d 的基本信息失败: %v", topLevelPlanID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 在内存中计算新的计数值和状态
|
||||||
|
newExecuteCount := plan.ExecuteCount + 1
|
||||||
|
newStatus := plan.Status // 默认为当前状态
|
||||||
|
|
||||||
|
// 如果是自动计划且达到执行次数上限,或计划是手动类型,则更新计划状态为已停止
|
||||||
|
if (plan.ExecutionType == models.PlanExecutionTypeAutomatic && plan.ExecuteNum > 0 && newExecuteCount >= plan.ExecuteNum) || plan.ExecutionType == models.PlanExecutionTypeManual {
|
||||||
|
newStatus = models.PlanStatusStopeed
|
||||||
|
s.logger.Infof("计划 %d 已完成执行,状态更新为 '执行完毕'。", topLevelPlanID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 使用专门的方法来原子性地更新计数值和状态
|
||||||
|
if err := s.planRepo.UpdatePlanStateAfterExecution(topLevelPlanID, newExecuteCount, newStatus); err != nil {
|
||||||
|
s.logger.Errorf("更新计划 %d 的执行后状态失败: %v", topLevelPlanID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 更新计划执行日志状态为完成
|
||||||
|
if err := s.executionLogRepo.UpdatePlanExecutionLogStatus(planLogID, models.ExecutionStatusCompleted); err != nil {
|
||||||
|
s.logger.Errorf("更新计划执行日志 %d 状态为 '完成' 失败: %v", planLogID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 调用共享的 Manager 来处理触发器更新逻辑
|
||||||
|
if err := s.analysisPlanTaskManager.CreateOrUpdateTrigger(topLevelPlanID); err != nil {
|
||||||
|
s.logger.Errorf("为计划 %d 创建/更新触发器失败: %v", topLevelPlanID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user