package handlers import ( "context" "encoding/json" "reflect" "sync" "time" "git.wishpal.cn/wishpal_ironfan/xframe/component/logger" "git.wishpal.cn/wishpal_ironfan/xframe/component/queue/asynq/internal/rate" "git.wishpal.cn/wishpal_ironfan/xframe/component/queue/asynq/internal/utils" "git.wishpal.cn/wishpal_ironfan/xframe/component/storage/redisrate" "github.com/hibiken/asynq" "github.com/pkg/errors" ) var handlers = map[string]IHandler{} var lock sync.RWMutex type IHandler interface { NewParam() (reflect.Value, error) Call(ctx context.Context, v reflect.Value, p reflect.Value) error } func getHandler(typ string) (IHandler, bool) { typ = utils.TrimUnifiedPattern(typ) lock.RLock() h, ok := handlers[typ] lock.RUnlock() return h, ok } func GenHandlerFunc(ctrl *rate.RateCtrl, key string, limitPerSecond int) func(ctx context.Context, task *asynq.Task) error { return func(ctx context.Context, task *asynq.Task) error { err := ctrl.Allow(ctx, key, redisrate.Limit{ Rate: limitPerSecond, Burst: limitPerSecond, Period: time.Second, }) if err != nil { return err } return handleFunc(ctx, task) } } func handleFunc(ctx context.Context, task *asynq.Task) (err error) { start := time.Now() defer func(ctx context.Context) { if err == nil { logger.WithContext(ctx).Infof("xcasynq handlefunc, use %v, task type %s, id %s, payload %s", time.Since(start), task.Type(), task.ResultWriter().TaskID(), task.Payload()) } }(ctx) f, ok := getHandler(task.Type()) if !ok { return errors.Errorf("no handler for %s", task.Type()) } param, err := f.NewParam() if err != nil { err = errors.Wrap(err, "NewParam") return err } err = json.Unmarshal(task.Payload(), param.Interface()) if err != nil { return err } p := reflect.ValueOf(f).FieldByName("Processor") return f.Call(ctx, param, p) }