xframe/component/queue/asynq/internal/handlers/handlers.go

74 lines
1.8 KiB
Go
Executable File

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