| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package fwhQueue
- import (
- "context"
- "fmt"
- "time"
- "fwh-toolbox-server/dto"
- task_core "fwh-toolbox-server/task/core"
- "github.com/hibiken/asynq"
- "go.uber.org/zap"
- )
- // 任务类型常量
- const (
- TaskTypeBatchDownload = "fwh:BatchDownload"
- TaskTypeCallFile = "fwh:CallFile"
- TaskTypeSiteAnalysis = "fwh:SiteAnalysis"
- TaskTypeShutdownStats = "fwh:ShutdownStatistics"
- TaskTypeSiteInfoUpdate = "fwh:SiteInfoUpdate"
- )
- // 队列名称
- const (
- QueueMain = "fwh:main" // 主任务队列(顺序执行)
- QueueDownload = "fwh:download" // 文件下载队列(可并发)
- )
- // Redis key 前缀
- const (
- // 子任务计数器 key: fwh:callfile:counter:{mainTaskId}
- callFileCounterPrefix = "fwh:callfile:counter:"
- // 子任务失败原因 key: fwh:callfile:failures:{mainTaskId}
- callFileFailuresPrefix = "fwh:callfile:failures:"
- )
- // 模块级变量
- var (
- TaskClient *asynq.Client
- inspector *asynq.Inspector
- )
- // InitFwhTaskQueue 初始化新的 FWH 任务队列
- // 通过 TaskCore 创建 Asynq Server(worker)、Client(入队)、Inspector(状态查询)
- func InitFwhTaskQueue(tc *task_core.TaskCore) {
- // 获取 Inspector(用于主任务轮询子任务状态)
- inspector = tc.Inspector.GetInspector()
- // 注册处理函数
- mux := asynq.NewServeMux()
- mux.HandleFunc(TaskTypeBatchDownload, handleBatchDownload)
- mux.HandleFunc(TaskTypeCallFile, handleCallFile)
- mux.HandleFunc(TaskTypeSiteAnalysis, handleSiteAnalysis)
- mux.HandleFunc(TaskTypeShutdownStats, handleShutdownStatistics)
- mux.HandleFunc(TaskTypeSiteInfoUpdate, handleSiteInfoUpdate)
- // 通过 TaskCore 创建任务 Server 和 Client
- TaskClient = tc.CreateTask(task_core.TaskConfig{
- Name: "FwhTask",
- SvrCfg: asynq.Config{
- Concurrency: 6, // 总并发数
- Queues: map[string]int{
- QueueDownload: 4, // 文件下载队列:4 个并发 worker
- QueueMain: 2, // 主任务队列:2 个并发 worker
- },
- // 错误处理
- ErrorHandler: asynq.ErrorHandlerFunc(func(ctx context.Context, task *asynq.Task, err error) {
- zap.L().Error("[fwhQueue] task failed",
- zap.String("type", task.Type()),
- zap.String("err", err.Error()),
- )
- }),
- // 重试延迟策略(指数退避)
- RetryDelayFunc: func(n int, e error, t *asynq.Task) time.Duration {
- return time.Duration(n*n) * 30 * time.Second // 30s, 2min, 4.5min
- },
- },
- Mux: mux,
- })
- zap.L().Info("[fwhQueue] initialized successfully")
- }
- // GetClient 获取 Asynq Client(供内部使用)
- func GetClient() *asynq.Client {
- return TaskClient
- }
- // GetInspector 获取 Asynq Inspector(供内部使用)
- func GetInspector() *asynq.Inspector {
- return inspector
- }
- // GetTaskInfoList 获取所有 FWH 队列中的任务列表(供外部查询)
- func GetTaskInfoList() ([]dto.BackgroundTaskItem, error) {
- if inspector == nil {
- return nil, fmt.Errorf("inspector not initialized")
- }
- var result []dto.BackgroundTaskItem
- queues := []string{QueueMain, QueueDownload}
- for _, queue := range queues {
- // 查询活跃任务(running)
- activeTasks, err := inspector.ListActiveTasks(queue, asynq.PageSize(100))
- if err == nil {
- for _, t := range activeTasks {
- result = append(result, dto.BackgroundTaskItem{
- Id: t.ID,
- Status: "running",
- Retry: int64(t.Retried),
- Payload: string(t.Payload),
- })
- }
- }
- // 查询等待中的任务(pending)
- pendingTasks, err := inspector.ListPendingTasks(queue, asynq.PageSize(100))
- if err == nil {
- for _, t := range pendingTasks {
- result = append(result, dto.BackgroundTaskItem{
- Id: t.ID,
- Status: "pending",
- Retry: int64(t.Retried),
- Payload: string(t.Payload),
- })
- }
- }
- // 查询重试中的任务(retry)
- retryTasks, err := inspector.ListRetryTasks(queue, asynq.PageSize(100))
- if err == nil {
- for _, t := range retryTasks {
- result = append(result, dto.BackgroundTaskItem{
- Id: t.ID,
- Status: "retry",
- Retry: int64(t.Retried),
- Payload: string(t.Payload),
- })
- }
- }
- // 查询已完成的任务(completed)
- completedTasks, err := inspector.ListCompletedTasks(queue, asynq.PageSize(100))
- if err == nil {
- for _, t := range completedTasks {
- result = append(result, dto.BackgroundTaskItem{
- Id: t.ID,
- Status: "completed",
- Retry: int64(t.Retried),
- Payload: string(t.Payload),
- })
- }
- }
- // 查询失败的任务(archived/failed)
- archivedTasks, err := inspector.ListArchivedTasks(queue, asynq.PageSize(100))
- if err == nil {
- for _, t := range archivedTasks {
- result = append(result, dto.BackgroundTaskItem{
- Id: t.ID,
- Status: "failed",
- Retry: int64(t.Retried),
- Payload: string(t.Payload),
- })
- }
- }
- }
- return result, nil
- }
- // newTaskID 生成固定格式的 TaskID,方便追踪
- func newTaskID(taskType string, id string) string {
- return fmt.Sprintf("%s:%s", taskType, id)
- }
|