实现意外获取Task后重新放回去
This commit is contained in:
@@ -11,8 +11,11 @@ import (
|
||||
// PendingTaskRepository 定义了与待执行任务队列交互的接口。
|
||||
type PendingTaskRepository interface {
|
||||
CreatePendingTasksInBatch(tasks []*models.PendingTask) error
|
||||
ClaimNextAvailableTask(excludePlanIDs []uint) (*models.TaskExecutionLog, error)
|
||||
RequeueTask(log *models.TaskExecutionLog) error
|
||||
// ClaimNextAvailableTask 原子地认领下一个可用的任务。
|
||||
// 它会同时返回被认领任务对应的日志对象,以及被删除的待办任务对象的内存副本。
|
||||
ClaimNextAvailableTask(excludePlanIDs []uint) (*models.TaskExecutionLog, *models.PendingTask, error)
|
||||
// RequeueTask 安全地将一个任务重新放回队列。
|
||||
RequeueTask(originalPendingTask *models.PendingTask) error
|
||||
}
|
||||
|
||||
// pendingTaskRepository 是使用 GORM 的具体实现。
|
||||
@@ -31,11 +34,11 @@ func (r *pendingTaskRepository) CreatePendingTasksInBatch(tasks []*models.Pendin
|
||||
}
|
||||
|
||||
// ClaimNextAvailableTask 以原子方式认领下一个可用的任务。
|
||||
func (r *pendingTaskRepository) ClaimNextAvailableTask(excludePlanIDs []uint) (*models.TaskExecutionLog, error) {
|
||||
func (r *pendingTaskRepository) ClaimNextAvailableTask(excludePlanIDs []uint) (*models.TaskExecutionLog, *models.PendingTask, error) {
|
||||
var log models.TaskExecutionLog
|
||||
var pendingTask models.PendingTask
|
||||
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
var pendingTask models.PendingTask
|
||||
query := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
Where("execute_at <= ?", time.Now()).
|
||||
Order("execute_at ASC")
|
||||
@@ -68,27 +71,26 @@ func (r *pendingTaskRepository) ClaimNextAvailableTask(excludePlanIDs []uint) (*
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &log, nil
|
||||
return &log, &pendingTask, nil
|
||||
}
|
||||
|
||||
// RequeueTask 安全地将一个已被认领但无法执行的任务放回队列。
|
||||
// 它在一个事务中原子地将日志状态恢复为 'waiting',并重新创建待办任务。
|
||||
func (r *pendingTaskRepository) RequeueTask(log *models.TaskExecutionLog) error {
|
||||
// RequeueTask 安全地将一个任务重新放回队列。
|
||||
// 它通过将原始 PendingTask 的 ID 重置为 0,并重新创建它来实现。
|
||||
func (r *pendingTaskRepository) RequeueTask(originalPendingTask *models.PendingTask) error {
|
||||
return r.db.Transaction(func(tx *gorm.DB) error {
|
||||
// 1. 将日志状态恢复为 waiting
|
||||
if err := tx.Model(log).Update("status", models.ExecutionStatusWaiting).Error; err != nil {
|
||||
if err := tx.Model(&models.TaskExecutionLog{}).Where("id = ?", originalPendingTask.TaskExecutionLogID).Update("status", models.ExecutionStatusWaiting).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 重新创建待办任务,立即执行
|
||||
newPendingTask := models.PendingTask{
|
||||
TaskID: log.TaskID,
|
||||
TaskExecutionLogID: log.ID,
|
||||
ExecuteAt: time.Now(),
|
||||
}
|
||||
return tx.Create(&newPendingTask).Error
|
||||
// 2. 关键:将传入的 PendingTask 的 ID 重置为 0。
|
||||
// 这会告诉 GORM,这是一个需要创建(INSERT)的新记录,而不是更新。
|
||||
originalPendingTask.ID = 0
|
||||
|
||||
// 3. 重新创建待办任务。GORM 会忽略掉已被重置的 ID,并让数据库生成一个新的主键。
|
||||
return tx.Create(originalPendingTask).Error
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user