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 } } } }