You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
373 lines
11 KiB
373 lines
11 KiB
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 |
|
} |
|
} |
|
}
|
|
|