214 lines
6.5 KiB
Go
214 lines
6.5 KiB
Go
package vqdtask
|
|
|
|
import (
|
|
"context"
|
|
"easyvqd/internal/core/vqd"
|
|
"easyvqd/pkg/vqdcms"
|
|
"fmt"
|
|
"log/slog"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
VqdPollingTaskMap = vqdcms.VqdTaskMap{M: make(map[string]*vqdcms.VQDHandle)}
|
|
TaskFlowMap *TaskFlow
|
|
)
|
|
|
|
func (c *Core) StartPolling() {
|
|
TaskFlowMap = NewTaskFlow(int(c.Cfg.VqdConfig.PollingNum))
|
|
c.UpdatePollingTask()
|
|
// 注册开始执行回调
|
|
TaskFlowMap.RegisterStartCallback(func(task Task, executeDuration time.Duration, timeout time.Duration) {
|
|
slog.Debug("[全局回调-开始]", "任务", task.ID(), "预期耗时", executeDuration, "超时阈值", timeout)
|
|
// 可扩展:记录任务启动时间、初始化监控指标、打印执行前日志等
|
|
c.AddPollingTaskVqd(task.ID(), task.GetPara(), task.GetHandleInfo())
|
|
})
|
|
TaskFlowMap.RegisterSuccessCallback(func(taskID string, executeDuration time.Duration, elapsed time.Duration) {
|
|
slog.Debug("[全局回调-成功]", "任务", taskID, "预期耗时", executeDuration, "实际耗时", elapsed)
|
|
// 可扩展:记录日志、更新监控指标、发送通知等
|
|
c.DelPollingTaskVqd(taskID)
|
|
})
|
|
|
|
// 注册失败回调
|
|
TaskFlowMap.RegisterFailCallback(func(taskID string, err error, elapsed time.Duration) {
|
|
slog.Debug("[全局回调-失败]", "任务", taskID, "原因", err, "实际耗时", elapsed)
|
|
// 可扩展:记录错误日志、触发告警、重试策略等
|
|
c.DelPollingTaskVqd(taskID)
|
|
})
|
|
|
|
// 注册超时回调
|
|
TaskFlowMap.RegisterTimeoutCallback(func(taskID string, timeout time.Duration, elapsed time.Duration) {
|
|
slog.Debug("[全局回调-超时]", "任务", taskID, "超时阈值", timeout, "实际耗时", elapsed)
|
|
// 可扩展:发送超时告警、调整任务超时配置等
|
|
c.DelPollingTaskVqd(taskID)
|
|
})
|
|
items, _, err := c.VqdTaskCore.FindVqdPollingAll()
|
|
if err == nil && len(items) > 0 {
|
|
for _, v := range items {
|
|
errs := c.AddPollingTask(v)
|
|
if errs != nil {
|
|
slog.Error("vqd polling add template", "err", errs.Error())
|
|
continue
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
}
|
|
// 启动任务流
|
|
TaskFlowMap.Start()
|
|
|
|
}
|
|
func (c *Core) StopPolling() {
|
|
if TaskFlowMap != nil {
|
|
// 停止任务流
|
|
TaskFlowMap.Close()
|
|
}
|
|
}
|
|
func (c *Core) HasRunningTask(chnId string) int {
|
|
pollingId := fmt.Sprintf("%s_polling", chnId)
|
|
if TaskFlowMap.HasRunning(pollingId) {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
func (c *Core) AddPollingTask(task *vqd.VqdPolling) error {
|
|
|
|
chnId := task.ChannelID
|
|
pollingId := fmt.Sprintf("%s_polling", chnId)
|
|
para := vqdcms.NewVQDPara(TaskFlowMap.TaskTemplate)
|
|
info := vqdcms.VQDHandleInfo{
|
|
ChannelID: chnId,
|
|
ChannelName: task.ChannelName,
|
|
TaskID: task.ID,
|
|
TaskName: "轮询",
|
|
TemplateID: TaskFlowMap.TaskTemplate.ID,
|
|
TemplateName: TaskFlowMap.TaskTemplate.Name,
|
|
PlanID: 0,
|
|
PlanName: "全量",
|
|
Plans: "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
|
}
|
|
newTask := NewPollingTask(pollingId, time.Duration(c.Cfg.VqdConfig.PollingTime)*time.Second, time.Duration(c.Cfg.VqdConfig.PollingTime+1)*time.Second, para, info)
|
|
TaskFlowMap.AddTask(newTask)
|
|
return nil
|
|
}
|
|
|
|
func (c *Core) UpdatePollingTask() {
|
|
cof := c.Cfg.VqdConfig
|
|
TaskFlowMap.BatchSetExecuteDuration(time.Duration(cof.PollingTime) * time.Second)
|
|
TaskFlowMap.BatchSetTimeout(time.Duration(cof.PollingTime+1) * time.Second)
|
|
TaskFlowMap.SetMaxConcurrent(int(cof.PollingNum))
|
|
|
|
taskTemplate, err := c.VqdTaskCore.GetIDVqdTaskTemplate(context.TODO(), int64(cof.PollingTemplate))
|
|
if err != nil {
|
|
slog.Error("vqd polling find template", "err", err.Error())
|
|
}
|
|
if taskTemplate != nil {
|
|
TaskFlowMap.SetTemplate(taskTemplate)
|
|
}
|
|
}
|
|
|
|
func (c *Core) DelPollingTask(chnId string) error {
|
|
pollingId := fmt.Sprintf("%s_polling", chnId)
|
|
TaskFlowMap.RemoveTask(pollingId, true)
|
|
c.DelPollingTaskVqd(pollingId)
|
|
return nil
|
|
}
|
|
|
|
func (c *Core) AddPollingTaskVqd(pollingId string, para vqdcms.VQDPara, info vqdcms.VQDHandleInfo) {
|
|
v := vqdcms.NewVQDHandle(c.ResultCb, c.HostCore, info).Create(para, info.Plans)
|
|
VqdPollingTaskMap.StoreChildMap(pollingId, v)
|
|
}
|
|
func (c *Core) DelPollingTaskVqd(pollingId string) {
|
|
v, ok := VqdPollingTaskMap.LoadTaskMap(pollingId)
|
|
if ok {
|
|
v.Destroy()
|
|
}
|
|
VqdPollingTaskMap.DeleteTaskMap(pollingId)
|
|
}
|
|
|
|
type PollingTask struct {
|
|
id string
|
|
timeout time.Duration
|
|
executeDuration time.Duration
|
|
info vqdcms.VQDHandleInfo
|
|
para vqdcms.VQDPara
|
|
mu sync.RWMutex // 任务配置修改锁
|
|
|
|
}
|
|
|
|
func NewPollingTask(id string, executeDuration, timeout time.Duration, para vqdcms.VQDPara, info vqdcms.VQDHandleInfo) *PollingTask {
|
|
return &PollingTask{
|
|
id: id,
|
|
timeout: timeout,
|
|
executeDuration: executeDuration,
|
|
para: para,
|
|
info: info,
|
|
}
|
|
}
|
|
|
|
func (d *PollingTask) ID() string { return d.id }
|
|
|
|
// Timeout 读取超时时间(读锁保护)
|
|
func (d *PollingTask) Timeout() time.Duration {
|
|
d.mu.RLock()
|
|
defer d.mu.RUnlock()
|
|
return d.timeout
|
|
}
|
|
func (d *PollingTask) GetPara() vqdcms.VQDPara {
|
|
d.mu.RLock()
|
|
defer d.mu.RUnlock()
|
|
return d.para
|
|
}
|
|
func (d *PollingTask) GetHandleInfo() vqdcms.VQDHandleInfo {
|
|
d.mu.RLock()
|
|
defer d.mu.RUnlock()
|
|
return d.info
|
|
}
|
|
|
|
// ExecuteDuration 读取执行时长(读锁保护)
|
|
func (d *PollingTask) ExecuteDuration() time.Duration {
|
|
d.mu.RLock()
|
|
defer d.mu.RUnlock()
|
|
return d.executeDuration
|
|
}
|
|
|
|
// SetTimeout 动态修改超时时间(写锁保护)
|
|
func (d *PollingTask) SetTimeout(newTimeout time.Duration) {
|
|
d.mu.Lock()
|
|
oldTimeout := d.timeout
|
|
d.timeout = newTimeout
|
|
d.mu.Unlock()
|
|
slog.Debug("任务超时时间修改", "id", d.id, "old", oldTimeout, "news", newTimeout)
|
|
}
|
|
|
|
// SetExecuteDuration 动态修改执行时长(写锁保护)
|
|
func (d *PollingTask) SetExecuteDuration(newDuration time.Duration) {
|
|
d.mu.Lock()
|
|
oldDuration := d.executeDuration
|
|
d.executeDuration = newDuration
|
|
d.mu.Unlock()
|
|
slog.Debug("任务执行时长修改", "id", d.id, "old", oldDuration, "news", newDuration)
|
|
}
|
|
|
|
func (d *PollingTask) Execute(ctx context.Context) error {
|
|
ticker := time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
// 执行时读取最新的执行时长配置
|
|
targetDuration := d.ExecuteDuration()
|
|
elapsed := 0 * time.Millisecond
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return fmt.Errorf("任务被取消: %v (预期执行: %v, 已执行: %v)", ctx.Err(), targetDuration, elapsed)
|
|
case <-ticker.C:
|
|
elapsed += 100 * time.Millisecond
|
|
if elapsed >= targetDuration {
|
|
fmt.Println("执行成功:", d.ID())
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|