发布 0.2.0:模型池自愈、探测修正、任务异步触发与删除加固
This commit is contained in:
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
@@ -46,6 +47,12 @@ type TaskService struct {
|
||||
entries map[uint]cron.EntryID
|
||||
// runMu 让租户删除等待在途执行结束,并阻止新执行读取删除前的任务快照。
|
||||
runMu sync.RWMutex
|
||||
// runningMu 保护 running:同一任务不允许并发重复执行
|
||||
// (cron 重叠触发静默跳过,手动触发返回 ErrTaskRunning)
|
||||
runningMu sync.Mutex
|
||||
running map[uint]bool
|
||||
// runWG 追踪手动触发的后台执行,Stop 时等待收尾
|
||||
runWG sync.WaitGroup
|
||||
|
||||
// snatchVarsMu 保护 snatchVars:runSnatch 抢满时写入成功通知变量,
|
||||
// execute 组装执行后快照时取走(一次性)
|
||||
@@ -63,6 +70,7 @@ func NewTaskService(db *gorm.DB, configs *OciConfigService, notifier *Notifier,
|
||||
settings: settings,
|
||||
cron: cron.New(),
|
||||
entries: map[uint]cron.EntryID{},
|
||||
running: map[uint]bool{},
|
||||
snatchIPWait: defaultSnatchIPWait,
|
||||
snatchVars: map[uint]map[string]string{},
|
||||
}
|
||||
@@ -86,10 +94,11 @@ func (s *TaskService) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop 停止调度并等待执行中的任务收尾,
|
||||
// Stop 停止调度并等待执行中的任务收尾(含手动触发的后台执行),
|
||||
// 保证任务产生的异步通知都已进入 Notifier 的等待队列。
|
||||
func (s *TaskService) Stop() {
|
||||
<-s.cron.Stop().Done()
|
||||
s.runWG.Wait()
|
||||
}
|
||||
|
||||
// healthCheckPayload 是测活任务参数;ociConfigIds 为空表示全部配置。
|
||||
@@ -356,7 +365,7 @@ func (s *TaskService) TaskLogs(ctx context.Context, id uint, limit int) ([]model
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
// RunTaskNow 立即执行一次任务并返回本次日志。
|
||||
// RunTaskNow 同步执行一次任务并返回本次日志(内部与测试使用;API 走 TriggerTask)。
|
||||
func (s *TaskService) RunTaskNow(ctx context.Context, id uint) (*model.TaskLog, error) {
|
||||
if _, err := s.GetTask(ctx, id); err != nil {
|
||||
return nil, err
|
||||
@@ -364,6 +373,43 @@ func (s *TaskService) RunTaskNow(ctx context.Context, id uint) (*model.TaskLog,
|
||||
return s.execute(id), nil
|
||||
}
|
||||
|
||||
// ErrTaskRunning 表示任务已有一次执行在途,拒绝重复触发。
|
||||
var ErrTaskRunning = errors.New("任务正在执行中,请稍候")
|
||||
|
||||
// TriggerTask 异步触发一次任务执行并立即返回;执行结果照常落任务日志与通知,
|
||||
// 由前端轮询呈现。同一任务在途时返回 ErrTaskRunning。
|
||||
func (s *TaskService) TriggerTask(ctx context.Context, id uint) error {
|
||||
if _, err := s.GetTask(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
if !s.beginRun(id) {
|
||||
return ErrTaskRunning
|
||||
}
|
||||
s.runWG.Add(1)
|
||||
go func() {
|
||||
defer s.runWG.Done()
|
||||
s.runHeld(id)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// beginRun 抢占任务的执行权;在途时返回 false。
|
||||
func (s *TaskService) beginRun(id uint) bool {
|
||||
s.runningMu.Lock()
|
||||
defer s.runningMu.Unlock()
|
||||
if s.running[id] {
|
||||
return false
|
||||
}
|
||||
s.running[id] = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *TaskService) endRun(id uint) {
|
||||
s.runningMu.Lock()
|
||||
delete(s.running, id)
|
||||
s.runningMu.Unlock()
|
||||
}
|
||||
|
||||
// schedule 把任务注册进 cron 调度。
|
||||
func (s *TaskService) schedule(task *model.Task) error {
|
||||
s.mu.Lock()
|
||||
@@ -412,9 +458,18 @@ func (s *TaskService) lockTenantCleanup() func() {
|
||||
return s.runMu.Unlock
|
||||
}
|
||||
|
||||
// execute 执行一次任务:加载 → 分派 → 更新任务状态并写日志,
|
||||
// 前后状态交给通知判定,只在状态变化时推送。
|
||||
// execute 执行一次任务:同一任务已有执行在途时静默跳过(cron 重叠触发防抖)。
|
||||
func (s *TaskService) execute(taskID uint) *model.TaskLog {
|
||||
if !s.beginRun(taskID) {
|
||||
return nil
|
||||
}
|
||||
return s.runHeld(taskID)
|
||||
}
|
||||
|
||||
// runHeld 在已持有执行权的前提下完成一次执行:加载 → 分派 → 更新任务状态并写日志,
|
||||
// 前后状态交给通知判定,只在状态变化时推送。
|
||||
func (s *TaskService) runHeld(taskID uint) *model.TaskLog {
|
||||
defer s.endRun(taskID)
|
||||
s.runMu.RLock()
|
||||
defer s.runMu.RUnlock()
|
||||
return s.executeLocked(taskID)
|
||||
|
||||
Reference in New Issue
Block a user