重构AnalysisPlanTaskManager
This commit is contained in:
@@ -8,6 +8,9 @@ import (
|
||||
// ExecutionLogRepository 定义了与执行日志交互的接口。
|
||||
// 这为服务层提供了一个清晰的契约,并允许在测试中轻松地进行模拟。
|
||||
type ExecutionLogRepository interface {
|
||||
UpdateLogStatusByIDs(logIDs []uint, status models.ExecutionStatus) error
|
||||
UpdateLogStatus(logID uint, status models.ExecutionStatus) error
|
||||
CreateTaskExecutionLog(log *models.TaskExecutionLog) error
|
||||
CreatePlanExecutionLog(log *models.PlanExecutionLog) error
|
||||
UpdatePlanExecutionLog(log *models.PlanExecutionLog) error
|
||||
CreateTaskExecutionLogsInBatch(logs []*models.TaskExecutionLog) error
|
||||
@@ -26,6 +29,23 @@ func NewGormExecutionLogRepository(db *gorm.DB) ExecutionLogRepository {
|
||||
return &gormExecutionLogRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *gormExecutionLogRepository) UpdateLogStatusByIDs(logIDs []uint, status models.ExecutionStatus) error {
|
||||
if len(logIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.db.Model(&models.TaskExecutionLog{}).
|
||||
Where("id IN ?", logIDs).
|
||||
Update("status", status).Error
|
||||
}
|
||||
|
||||
func (r *gormExecutionLogRepository) UpdateLogStatus(logID uint, status models.ExecutionStatus) error {
|
||||
return r.db.Model(&models.TaskExecutionLog{}).Where("id = ?", logID).Update("status", status).Error
|
||||
}
|
||||
|
||||
func (r *gormExecutionLogRepository) CreateTaskExecutionLog(log *models.TaskExecutionLog) error {
|
||||
return r.db.Create(log).Error
|
||||
}
|
||||
|
||||
// CreatePlanExecutionLog 为一次计划执行创建一条新的日志条目。
|
||||
func (r *gormExecutionLogRepository) CreatePlanExecutionLog(log *models.PlanExecutionLog) error {
|
||||
return r.db.Create(log).Error
|
||||
@@ -41,6 +61,9 @@ func (r *gormExecutionLogRepository) UpdatePlanExecutionLog(log *models.PlanExec
|
||||
// CreateTaskExecutionLogsInBatch 在一次数据库调用中创建多个任务执行日志条目。
|
||||
// 这是“预写日志”步骤的关键。
|
||||
func (r *gormExecutionLogRepository) CreateTaskExecutionLogsInBatch(logs []*models.TaskExecutionLog) error {
|
||||
if len(logs) == 0 {
|
||||
return nil
|
||||
}
|
||||
// GORM 的 Create 传入一个切片指针会执行批量插入。
|
||||
return r.db.Create(&logs).Error
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||
@@ -10,6 +11,10 @@ import (
|
||||
|
||||
// PendingTaskRepository 定义了与待执行任务队列交互的接口。
|
||||
type PendingTaskRepository interface {
|
||||
FindAllPendingTasks() ([]models.PendingTask, error)
|
||||
FindPendingTriggerByPlanID(planID uint) (*models.PendingTask, error)
|
||||
DeletePendingTasksByIDs(ids []uint) error
|
||||
CreatePendingTask(task *models.PendingTask) error
|
||||
CreatePendingTasksInBatch(tasks []*models.PendingTask) error
|
||||
// ClaimNextAvailableTask 原子地认领下一个可用的任务。
|
||||
// 它会同时返回被认领任务对应的日志对象,以及被删除的待办任务对象的内存副本。
|
||||
@@ -28,8 +33,41 @@ func NewGormPendingTaskRepository(db *gorm.DB) PendingTaskRepository {
|
||||
return &gormPendingTaskRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *gormPendingTaskRepository) FindAllPendingTasks() ([]models.PendingTask, error) {
|
||||
var tasks []models.PendingTask
|
||||
// 预加载 Task 以便后续访问 Task.PlanID
|
||||
err := r.db.Preload("Task").Find(&tasks).Error
|
||||
return tasks, err
|
||||
}
|
||||
|
||||
func (r *gormPendingTaskRepository) FindPendingTriggerByPlanID(planID uint) (*models.PendingTask, error) {
|
||||
var pendingTask models.PendingTask
|
||||
err := r.db.
|
||||
Joins("JOIN tasks ON tasks.id = pending_tasks.task_id").
|
||||
Where("tasks.plan_id = ? AND tasks.type = ?", planID, models.TaskPlanAnalysis).
|
||||
First(&pendingTask).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil // 未找到不是错误
|
||||
}
|
||||
return &pendingTask, err
|
||||
}
|
||||
|
||||
func (r *gormPendingTaskRepository) DeletePendingTasksByIDs(ids []uint) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.db.Where("id IN ?", ids).Delete(&models.PendingTask{}).Error
|
||||
}
|
||||
|
||||
func (r *gormPendingTaskRepository) CreatePendingTask(task *models.PendingTask) error {
|
||||
return r.db.Create(task).Error
|
||||
}
|
||||
|
||||
// CreatePendingTasksInBatch 在一次数据库调用中创建多个待执行任务条目。
|
||||
func (r *gormPendingTaskRepository) CreatePendingTasksInBatch(tasks []*models.PendingTask) error {
|
||||
if len(tasks) == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.db.Create(&tasks).Error
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,12 @@ type PlanRepository interface {
|
||||
DeleteTask(id int) error
|
||||
// FindPlanAnalysisTaskByParamsPlanID 根据Parameters中的ParamsPlanID字段值查找TaskPlanAnalysis类型的Task
|
||||
FindPlanAnalysisTaskByParamsPlanID(paramsPlanID uint) (*models.Task, error)
|
||||
// FindRunnablePlans 获取所有应执行的计划
|
||||
FindRunnablePlans() ([]*models.Plan, error)
|
||||
// FindDisabledAndStoppedPlans 获取所有已禁用或已停止的计划
|
||||
FindDisabledAndStoppedPlans() ([]*models.Plan, error)
|
||||
// FindPlanAnalysisTaskByPlanID 根据 PlanID 找到其关联的 'plan_analysis' 任务
|
||||
FindPlanAnalysisTaskByPlanID(planID uint) (*models.Task, error)
|
||||
}
|
||||
|
||||
// gormPlanRepository 是 PlanRepository 的 GORM 实现
|
||||
@@ -565,15 +571,56 @@ func (r *gormPlanRepository) createPlanAnalysisTask(tx *gorm.DB, plan *models.Pl
|
||||
return tx.Create(task).Error
|
||||
}
|
||||
|
||||
// updatePlanAnalysisTask 使用简单粗暴的删除再创建方式实现更新, 以控制AnalysisPlanTask的定义全部在createPlanAnalysisTask方法中
|
||||
// updatePlanAnalysisTask 使用更安全的方式更新触发器任务
|
||||
func (r *gormPlanRepository) updatePlanAnalysisTask(tx *gorm.DB, plan *models.Plan) error {
|
||||
task, err := r.findPlanAnalysisTaskByParamsPlanID(tx, plan.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
task, err := r.findPlanAnalysisTask(tx, plan.ID)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("查找现有计划分析任务失败: %w", err)
|
||||
}
|
||||
err = r.deleteTask(tx, task.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
// 如果触发器任务不存在,则创建一个
|
||||
if task == nil {
|
||||
return r.createPlanAnalysisTask(tx, plan)
|
||||
}
|
||||
return r.createPlanAnalysisTask(tx, plan)
|
||||
|
||||
// 如果存在,则更新它的名称和描述以反映计划的最新信息
|
||||
task.Name = fmt.Sprintf("'%s'计划触发器", plan.Name)
|
||||
task.Description = fmt.Sprintf("计划名: %s, 计划ID: %d", plan.Name, plan.ID)
|
||||
|
||||
return tx.Save(task).Error
|
||||
}
|
||||
|
||||
func (r *gormPlanRepository) FindRunnablePlans() ([]*models.Plan, error) {
|
||||
var plans []*models.Plan
|
||||
err := r.db.
|
||||
Where("status = ?", models.PlanStatusEnabled).
|
||||
Where(
|
||||
r.db.Where("execution_type = ?", models.PlanExecutionTypeManual).
|
||||
Or("execution_type = ? AND (execute_num = 0 OR execute_count < execute_num)", models.PlanExecutionTypeAutomatic),
|
||||
).
|
||||
Find(&plans).Error
|
||||
return plans, err
|
||||
}
|
||||
|
||||
func (r *gormPlanRepository) FindDisabledAndStoppedPlans() ([]*models.Plan, error) {
|
||||
var plans []*models.Plan
|
||||
err := r.db.
|
||||
Where("status = ? OR status = ?", models.PlanStatusDisabled, models.PlanStatusStopeed).
|
||||
Find(&plans).Error
|
||||
return plans, err
|
||||
}
|
||||
|
||||
// findPlanAnalysisTask 是一个内部使用的、更高效的查找方法
|
||||
func (r *gormPlanRepository) findPlanAnalysisTask(tx *gorm.DB, planID uint) (*models.Task, error) {
|
||||
var task models.Task
|
||||
err := tx.Where("plan_id = ? AND type = ?", planID, models.TaskPlanAnalysis).First(&task).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil // 未找到不是错误,返回nil, nil
|
||||
}
|
||||
return &task, err
|
||||
}
|
||||
|
||||
// FindPlanAnalysisTaskByPlanID 是暴露给外部的公共方法
|
||||
func (r *gormPlanRepository) FindPlanAnalysisTaskByPlanID(planID uint) (*models.Task, error) {
|
||||
return r.findPlanAnalysisTask(r.db, planID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user