package asynq import ( "context" "encoding/json" "net/http" "reflect" "git.wishpal.cn/wishpal_ironfan/xframe/base/proc" "git.wishpal.cn/wishpal_ironfan/xframe/component/queue/asynq/internal/handlers" "git.wishpal.cn/wishpal_ironfan/xframe/component/storage/redis" "github.com/hibiken/asynq" "github.com/pkg/errors" ) var ( xcAsynq = new(XcAsynq) ) type Config struct { redis.RedisConf // 可选 DefaultQueueQps int `json:",default=500"` // 常规队列的qps限制,默认500 SlowQueueQps int `json:",default=50"` // 慢速队列的qps限制,默认50 } // Init 初始化相关资源,但不开始执行异步任务 func Init(ctx context.Context, cfg *Config) error { return xcAsynq.Init(ctx, cfg) } // Start 真的开始执行异步任务。和Init拆开,以防止handler依赖的模块还没初始化好(比如mongo连接) func Start() error { if err := xcAsynq.Start(); err != nil { return err } proc.AddShutdownListener(func() { Stop() }) return nil } // Stop 优雅关闭异步任务 func Stop() { if xcAsynq.server == nil { return } xcAsynq.server.Stop() xcAsynq.server.Shutdown() } // MustRegistHandler 注册handler,失败则panic。 // 支持的T类型:map、slice、array、struct、string/int等,及其指针。 // 不支持:interface{}。 func MustRegistHandler[T any](typ string, f func(context.Context, T) error) { handlers.MustRegistHandler(typ, f) } // MustRegistHttpHandler // 业务不要直接用,框架用于处理异步http请求 func MustRegistHttpHandler(typ string, f http.HandlerFunc) { handlers.MustRegistHttpHandler(typ, f) } func GenHttpTaskPayload(r *http.Request) *JsonHelper { return Json(handlers.RequestToPayload(r)) } // JsonHelper 封装data来获得MarshalBinary方法 type JsonHelper struct { data interface{} } func (j JsonHelper) MarshalBinary() ([]byte, error) { return json.Marshal(j.data) } // TaskData 兼容的task数据类型 type TaskData interface { []byte | *JsonHelper } // Json 封装data以支持自动json序列化 func Json(data interface{}) *JsonHelper { return &JsonHelper{data: data} } // AddTask 添加一个常规速度的任务 func AddTask[T TaskData](ctx context.Context, typ string, payload T, opts ...asynq.Option) (info *asynq.TaskInfo, err error) { return addTask[T](ctx, queueDefault, typ, payload, opts...) } // AddSlowTask 添加一个低速的任务 func AddSlowTask[T TaskData](ctx context.Context, typ string, payload T, opts ...asynq.Option) (info *asynq.TaskInfo, err error) { return addTask[T](ctx, queueSlow, typ, payload, opts...) } func addTask[T TaskData](ctx context.Context, queue, typ string, data T, opts ...asynq.Option) (info *asynq.TaskInfo, err error) { var payload []byte switch tmp := interface{}(data).(type) { case []byte: payload = tmp case *JsonHelper: payload, err = tmp.MarshalBinary() if err != nil { err = errors.Wrap(err, "JsonHelper.MarshalBinary") return } default: err = errors.Errorf("unexpected data type: %v", reflect.TypeOf(data)) return } return xcAsynq.addTask(ctx, queue, typ, payload, opts...) }