374 lines
11 KiB
Go
374 lines
11 KiB
Go
|
package service
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"encoding/json"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"strings"
|
|||
|
"sync"
|
|||
|
|
|||
|
"go-common/app/job/main/aegis/model"
|
|||
|
"go-common/library/log"
|
|||
|
"go-common/library/queue/databus"
|
|||
|
|
|||
|
pkgerr "github.com/pkg/errors"
|
|||
|
)
|
|||
|
|
|||
|
//RscHandler .
|
|||
|
type RscHandler interface {
|
|||
|
CheckMessage(json.RawMessage) (interface{}, error)
|
|||
|
HandleMessage(context.Context, interface{}) error
|
|||
|
}
|
|||
|
|
|||
|
//TaskHandler .
|
|||
|
type TaskHandler interface {
|
|||
|
CheckMessage(*databus.Message) (interface{}, error)
|
|||
|
HandleMessage(context.Context, interface{}) error
|
|||
|
}
|
|||
|
|
|||
|
var (
|
|||
|
_ TaskHandler = baseTaskHandler{}
|
|||
|
_ TaskHandler = dynamicTaskHandler{}
|
|||
|
_ RscHandler = baseResourceAddHandler{}
|
|||
|
_ RscHandler = mangaResourceAddHandler{}
|
|||
|
_ RscHandler = baseResourceUpdateHandler{}
|
|||
|
_ RscHandler = baseResourceCancelHandler{}
|
|||
|
)
|
|||
|
|
|||
|
//单例
|
|||
|
var (
|
|||
|
basehandleTask *baseTaskHandler
|
|||
|
basehandleRscAdd *baseResourceAddHandler
|
|||
|
basehandleRscUpdate *baseResourceUpdateHandler
|
|||
|
basehandleRscCancel *baseResourceCancelHandler
|
|||
|
dynamicHandleTask *dynamicTaskHandler
|
|||
|
mangaHandelRscAdd *mangaResourceAddHandler
|
|||
|
once sync.Once
|
|||
|
)
|
|||
|
|
|||
|
//ERROR
|
|||
|
var (
|
|||
|
ErrTaskDuplicate = errors.New("重复任务")
|
|||
|
ErrTaskFlowInvalid = errors.New("流程失效")
|
|||
|
ErrTaskResourceInvalid = errors.New("资源失效")
|
|||
|
ErrInvalidMsg = errors.New("无效消息")
|
|||
|
ErrHandlerMiss = errors.New("handler NotFound")
|
|||
|
)
|
|||
|
|
|||
|
//prefix
|
|||
|
var (
|
|||
|
_prefixTask = "task_"
|
|||
|
_prefixRscAdd = "add_"
|
|||
|
_prefixRscUpdate = "update_"
|
|||
|
_prefixRscCancel = "cancel_"
|
|||
|
)
|
|||
|
|
|||
|
//业务ID
|
|||
|
var (
|
|||
|
_bizidDynamic = 1
|
|||
|
_bizidManga = 2
|
|||
|
)
|
|||
|
|
|||
|
func (s *Service) registerRscHandler(key string, handler RscHandler) {
|
|||
|
s.rschandle[key] = handler
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) registerTaskHandler(key string, handler TaskHandler) {
|
|||
|
s.taskhandle[key] = handler
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) findTaskHandler(key string) TaskHandler {
|
|||
|
if handler, ok := s.taskhandle[key]; ok {
|
|||
|
return handler
|
|||
|
}
|
|||
|
log.Warn("key(%s)没找到任务的处理器,根据类型使用默认handler", key)
|
|||
|
return s.getdynamicTaskHandler()
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) findRscHandler(key string) RscHandler {
|
|||
|
if handler, ok := s.rschandle[key]; ok {
|
|||
|
return handler
|
|||
|
}
|
|||
|
|
|||
|
log.Warn("key(%s)没找到业务的处理器,根据类型使用默认handler", key)
|
|||
|
switch {
|
|||
|
case strings.HasPrefix(key, _prefixRscAdd):
|
|||
|
return s.getbaseResourceAddHandler()
|
|||
|
case strings.HasPrefix(key, _prefixRscUpdate):
|
|||
|
return s.getbaseResourceUpdateHandler()
|
|||
|
case strings.HasPrefix(key, _prefixRscCancel):
|
|||
|
return s.getbaseResourceCancelHandler()
|
|||
|
default:
|
|||
|
return nil
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//TODO 先写死吧,之后可以根据配置里面的类名用反射实例化
|
|||
|
func initHandler(s *Service) {
|
|||
|
var (
|
|||
|
dynamicTask = fmt.Sprintf("%s%d", _prefixTask, _bizidDynamic)
|
|||
|
dynamicRscAdd = fmt.Sprintf("%s%d", _prefixRscAdd, _bizidDynamic)
|
|||
|
dynamicRscUpdate = fmt.Sprintf("%s%d", _prefixRscUpdate, _bizidDynamic)
|
|||
|
dynamicRscCancel = fmt.Sprintf("%s%d", _prefixRscCancel, _bizidDynamic)
|
|||
|
managaTask = fmt.Sprintf("%s%d", _prefixTask, _bizidManga)
|
|||
|
managaRscAdd = fmt.Sprintf("%s%d", _prefixRscAdd, _bizidManga)
|
|||
|
managaRscUpdate = fmt.Sprintf("%s%d", _prefixRscUpdate, _bizidManga)
|
|||
|
managaRscCancel = fmt.Sprintf("%s%d", _prefixRscCancel, _bizidManga)
|
|||
|
)
|
|||
|
s.rschandle = make(map[string]RscHandler)
|
|||
|
s.taskhandle = make(map[string]TaskHandler)
|
|||
|
|
|||
|
once.Do(func() {
|
|||
|
basehandleTask = &baseTaskHandler{Service: s}
|
|||
|
basehandleRscAdd = &baseResourceAddHandler{Service: s}
|
|||
|
basehandleRscUpdate = &baseResourceUpdateHandler{Service: s}
|
|||
|
basehandleRscCancel = &baseResourceCancelHandler{Service: s}
|
|||
|
dynamicHandleTask = &dynamicTaskHandler{baseTaskHandler: baseTaskHandler{Service: s}}
|
|||
|
mangaHandelRscAdd = &mangaResourceAddHandler{baseResourceAddHandler: baseResourceAddHandler{Service: s}}
|
|||
|
})
|
|||
|
|
|||
|
s.registerRscHandler(dynamicRscAdd, s.getbaseResourceAddHandler())
|
|||
|
s.registerRscHandler(dynamicRscUpdate, s.getbaseResourceUpdateHandler())
|
|||
|
s.registerRscHandler(dynamicRscCancel, s.getbaseResourceCancelHandler())
|
|||
|
s.registerRscHandler(managaRscAdd, s.getmangaResourceAddHandler())
|
|||
|
s.registerRscHandler(managaRscUpdate, s.getbaseResourceUpdateHandler())
|
|||
|
s.registerRscHandler(managaRscCancel, s.getbaseResourceCancelHandler())
|
|||
|
|
|||
|
s.registerTaskHandler(managaTask, s.getbaseTaskHandler())
|
|||
|
s.registerTaskHandler(dynamicTask, s.getdynamicTaskHandler())
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) getbaseTaskHandler() *baseTaskHandler {
|
|||
|
return basehandleTask
|
|||
|
}
|
|||
|
func (s *Service) getbaseResourceAddHandler() *baseResourceAddHandler {
|
|||
|
return basehandleRscAdd
|
|||
|
}
|
|||
|
func (s *Service) getbaseResourceUpdateHandler() *baseResourceUpdateHandler {
|
|||
|
return basehandleRscUpdate
|
|||
|
}
|
|||
|
func (s *Service) getbaseResourceCancelHandler() *baseResourceCancelHandler {
|
|||
|
return basehandleRscCancel
|
|||
|
}
|
|||
|
func (s *Service) getdynamicTaskHandler() *dynamicTaskHandler {
|
|||
|
return dynamicHandleTask
|
|||
|
}
|
|||
|
func (s *Service) getmangaResourceAddHandler() *mangaResourceAddHandler {
|
|||
|
return mangaHandelRscAdd
|
|||
|
}
|
|||
|
|
|||
|
//解析验证message
|
|||
|
/*
|
|||
|
TODO
|
|||
|
根据DispatchLimit,动态设置分发数量
|
|||
|
*/
|
|||
|
func (s *Service) checkTaskMsg(msg *databus.Message) (*model.Task, error) {
|
|||
|
taskMsg := new(model.CreateTaskMsg)
|
|||
|
if err := json.Unmarshal(msg.Value, taskMsg); err != nil {
|
|||
|
log.Error("checkTaskMsg key(%s) value(%s)", msg.Key, string(msg.Value))
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
if taskMsg.DispatchLimit == 0 || taskMsg.FlowID == 0 || taskMsg.RID == 0 {
|
|||
|
log.Error("checkTaskMsg key(%s) value(%s)", msg.Key, string(msg.Value))
|
|||
|
return nil, ErrTaskResourceInvalid
|
|||
|
}
|
|||
|
|
|||
|
if s.dao.CheckTask(context.Background(), taskMsg.FlowID, taskMsg.RID) > 0 {
|
|||
|
return nil, ErrTaskDuplicate
|
|||
|
}
|
|||
|
|
|||
|
ok, err := s.dao.CheckFlow(context.TODO(), taskMsg.RID, taskMsg.FlowID)
|
|||
|
if !ok || err != nil {
|
|||
|
return nil, ErrTaskFlowInvalid
|
|||
|
}
|
|||
|
|
|||
|
//先兼容旧的task消息,没有传bizid
|
|||
|
if taskMsg.BizID == 0 {
|
|||
|
res, err := s.dao.Resource(context.Background(), taskMsg.RID)
|
|||
|
if err != nil || res == nil {
|
|||
|
return nil, ErrTaskResourceInvalid
|
|||
|
}
|
|||
|
taskMsg.BizID = res.BusinessID
|
|||
|
}
|
|||
|
|
|||
|
return &model.Task{
|
|||
|
BusinessID: taskMsg.BizID,
|
|||
|
FlowID: taskMsg.FlowID,
|
|||
|
RID: taskMsg.RID,
|
|||
|
}, nil
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) writeTaskToDB(c context.Context, task *model.Task) error {
|
|||
|
return s.dao.CreateTask(c, task)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) checkRscAddMsg(msg json.RawMessage) (*model.AddOption, error) {
|
|||
|
addMsg := new(model.AddOption)
|
|||
|
if err := json.Unmarshal(msg, addMsg); err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
if addMsg.BusinessID == 0 || len(addMsg.OID) == 0 {
|
|||
|
return nil, ErrInvalidMsg
|
|||
|
}
|
|||
|
return addMsg, nil
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) writeRscAdd(c context.Context, opt *model.AddOption) error {
|
|||
|
//TODO 根据错误号重试
|
|||
|
return s.dao.RscAdd(c, opt)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) checkRscUpdateMsg(msg json.RawMessage) (*model.UpdateOption, error) {
|
|||
|
updateMsg := new(model.UpdateOption)
|
|||
|
if err := json.Unmarshal(msg, updateMsg); err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
if updateMsg.BusinessID == 0 || len(updateMsg.OID) == 0 || len(updateMsg.Update) == 0 {
|
|||
|
return nil, ErrInvalidMsg
|
|||
|
}
|
|||
|
return updateMsg, nil
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) writeRscUpdate(c context.Context, opt *model.UpdateOption) error {
|
|||
|
return s.dao.RscUpdate(c, opt)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) checkRscCancelMsg(msg json.RawMessage) (*model.CancelOption, error) {
|
|||
|
cancelMsg := new(model.CancelOption)
|
|||
|
if err := json.Unmarshal(msg, cancelMsg); err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
if cancelMsg.BusinessID == 0 || len(cancelMsg.Oids) == 0 {
|
|||
|
return nil, ErrInvalidMsg
|
|||
|
}
|
|||
|
return cancelMsg, nil
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) writeRscCancel(c context.Context, opt *model.CancelOption) error {
|
|||
|
return s.dao.RscCancel(c, opt)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) newrsc(msg *databus.Message) (interface{}, error) {
|
|||
|
log.Info("databusgroup new msg key(%+v) partition(%d) offset(%d) value(%s) ", msg.Key, msg.Partition, msg.Offset, string(msg.Value))
|
|||
|
|
|||
|
rscmsg := new(model.RscMsg)
|
|||
|
if err := json.Unmarshal(msg.Value, rscmsg); err != nil {
|
|||
|
log.Error("databusgroup json.Unmarshal for msg(%+v)", string(msg.Value))
|
|||
|
return nil, ErrInvalidMsg
|
|||
|
}
|
|||
|
|
|||
|
key := fmt.Sprintf("%s_%d", rscmsg.Action, rscmsg.BizID)
|
|||
|
handler := s.findRscHandler(key)
|
|||
|
if handler == nil {
|
|||
|
log.Error("databusgroup can not find handler for msg key(%+v)", key)
|
|||
|
return nil, ErrHandlerMiss
|
|||
|
}
|
|||
|
data, err := handler.CheckMessage(rscmsg.Raw)
|
|||
|
if err != nil {
|
|||
|
log.Error("databusgroup new msg key(%+v) partition(%d) offset(%d) value(%s) CheckMessage(%v)", msg.Key, msg.Partition, msg.Offset, string(msg.Value), pkgerr.WithStack(err))
|
|||
|
}
|
|||
|
return data, err
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) splitrsc(msg *databus.Message, data interface{}) int {
|
|||
|
switch t := data.(type) {
|
|||
|
case *model.AddOption:
|
|||
|
return int(t.BusinessID)
|
|||
|
case *model.UpdateOption:
|
|||
|
return int(t.BusinessID)
|
|||
|
case *model.CancelOption:
|
|||
|
return int(t.BusinessID)
|
|||
|
default:
|
|||
|
return 0
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) dorsc(bmsgs []interface{}) {
|
|||
|
for _, msg := range bmsgs {
|
|||
|
log.Info("databusgroup do msg(%+v)", msg)
|
|||
|
var key string
|
|||
|
switch t := msg.(type) {
|
|||
|
case *model.AddOption:
|
|||
|
key = fmt.Sprintf("%s%d", _prefixRscAdd, t.BusinessID)
|
|||
|
case *model.UpdateOption:
|
|||
|
key = fmt.Sprintf("%s%d", _prefixRscUpdate, t.BusinessID)
|
|||
|
case *model.CancelOption:
|
|||
|
key = fmt.Sprintf("%s%d", _prefixRscCancel, t.BusinessID)
|
|||
|
default:
|
|||
|
log.Error("databusgroup unknow msg(%+v)", msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
handler := s.findRscHandler(key)
|
|||
|
if handler == nil {
|
|||
|
log.Error("databusgroup msg(%+v) handler NotFound", msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
if err := handler.HandleMessage(context.Background(), msg); err != nil {
|
|||
|
log.Error("databusgroup msg(%+v) handler err(%v)", msg, pkgerr.WithStack(err))
|
|||
|
continue
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) newtask(msg *databus.Message) (interface{}, error) {
|
|||
|
log.Info("databusgroup newtask msg key(%+v) partition(%d) offset(%d) value(%s) ", msg.Key, msg.Partition, msg.Offset, string(msg.Value))
|
|||
|
|
|||
|
taskmsg := new(model.CreateTaskMsg)
|
|||
|
if err := json.Unmarshal(msg.Value, taskmsg); err != nil {
|
|||
|
log.Error("databusgroup newtask json.Unmarshal for msg(%+v)", string(msg.Value))
|
|||
|
return nil, ErrInvalidMsg
|
|||
|
}
|
|||
|
|
|||
|
key := fmt.Sprintf("%s%d", _prefixTask, taskmsg.BizID)
|
|||
|
handler := s.findTaskHandler(key)
|
|||
|
if handler == nil {
|
|||
|
log.Error("databusgroup can not find handler for msg key(%+v)", key)
|
|||
|
return nil, ErrHandlerMiss
|
|||
|
}
|
|||
|
data, err := handler.CheckMessage(msg)
|
|||
|
if err != nil {
|
|||
|
errmsg := fmt.Sprintf("databusgroup new msg key(%+v) partition(%d) offset(%d) value(%s) CheckMessage(%v)", msg.Key, msg.Partition, msg.Offset, string(msg.Value), pkgerr.WithStack(err))
|
|||
|
if err == ErrTaskDuplicate {
|
|||
|
log.Warn(errmsg)
|
|||
|
} else {
|
|||
|
log.Error(errmsg)
|
|||
|
}
|
|||
|
}
|
|||
|
return data, err
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) splittask(msg *databus.Message, data interface{}) int {
|
|||
|
if t, ok := data.(*model.Task); ok {
|
|||
|
return int(t.BusinessID)
|
|||
|
}
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) dotask(bmsgs []interface{}) {
|
|||
|
for _, msg := range bmsgs {
|
|||
|
log.Info("databusgroup dotask msg(%+v)", msg)
|
|||
|
var key string
|
|||
|
if t, ok := msg.(*model.Task); ok {
|
|||
|
key = fmt.Sprintf("%s%d", _prefixTask, t.BusinessID)
|
|||
|
} else {
|
|||
|
log.Error("databusgroup dotask unknow msg(%+v)", msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
handler := s.findTaskHandler(key)
|
|||
|
if handler == nil {
|
|||
|
log.Error("databusgroup dotask msg(%+v) handler NotFound", msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
if err := handler.HandleMessage(context.Background(), msg); err != nil {
|
|||
|
log.Error("databusgroup dotask msg(%+v) handler err(%v)", msg, pkgerr.WithStack(err))
|
|||
|
continue
|
|||
|
}
|
|||
|
}
|
|||
|
}
|