Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"appeal.go",
"expire.go",
"notify.go",
"queue.go",
"service.go",
"workflow.go",
],
importpath = "go-common/app/job/main/workflow/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/workflow/model/param:go_default_library",
"//app/job/main/workflow/conf:go_default_library",
"//app/job/main/workflow/dao:go_default_library",
"//app/job/main/workflow/model:go_default_library",
"//app/service/main/workflow/model:go_default_library",
"//library/database/elastic:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/errgroup.v2:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["service_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/workflow/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,404 @@
package service
import (
"context"
"time"
"go-common/app/job/main/workflow/model"
"go-common/library/log"
"go-common/library/sync/errgroup.v2"
)
// 工作台单条过期
func (s *Service) singleExpireproc() {
errGroup := errgroup.Group{}
for {
for _, attr := range s.businessAttr {
if attr.DealType != model.PDealType {
continue
}
time.Sleep(1 * time.Second)
errGroup.Go(func(ctx context.Context) error {
return s.singleExpire(ctx, attr.Bid)
})
}
errGroup.Wait()
}
}
func (s *Service) singleExpire(c context.Context, bid int) (err error) {
var delIDs []int64
if delIDs, err = s.dao.SingleExpire(c, bid); err != nil {
log.Error("s.dao.SingleExpire() bid:%d error: %v", bid, err)
return
}
if len(delIDs) == 0 {
return
}
log.Info("bid(%d) apid in (%v) are single expire", bid, delIDs)
// set db state
if err = s.dao.SetAppealAssignState(c, delIDs, model.AssignStateNotDispatch); err != nil {
log.Error("s.dao.SetAppealAssignState() error: %v", err)
return
}
if err = s.dao.DelSingleExpire(c, bid, delIDs); err != nil {
log.Error("s.dao.SetSingleExpire() bid:%d error: %v", bid, err)
return
}
if err = s.delRelatedMissions(c, bid, delIDs); err != nil {
log.Error("s.delRelatedMissions() error: %v", err)
}
return
}
// 反馈整体过期
func (s *Service) overallExpireproc() {
errGroup := errgroup.Group{}
for {
for _, attr := range s.businessAttr {
if attr.DealType != model.PDealType {
continue
}
time.Sleep(1 * time.Second)
errGroup.Go(func(ctx context.Context) error {
return s.overallExpire(ctx, attr.Bid)
})
}
errGroup.Wait()
}
}
func (s *Service) overallExpire(c context.Context, bid int) (err error) {
time.Sleep(10 * time.Second)
cond := model.AppealSearchCond{
Fields: []string{"id"},
Bid: []int{bid},
AssignState: []int8{model.AssignStatePoped},
TransferState: []int8{model.TransferStatePendingSystemReply},
DTimeTo: time.Now().Add(-time.Minute * 5).Format("2006-01-02 15:04:05"),
PS: 101,
PN: 1,
Order: "id",
Sort: "desc",
}
var res *model.AppealSearchRes
if res, err = s.dao.SearchAppeal(c, cond); err != nil {
log.Error("s.dao.SearchAppeal() error(%+v)", err)
return
}
if len(res.Result) == 0 {
log.Warn("no appeal is expire overall")
return
}
ids := make([]int64, 0, len(res.Result))
for _, r := range res.Result {
ids = append(ids, r.ID)
}
log.Info("apids(%v) are expire overall", ids)
if err = s.delRelatedMissions(c, bid, ids); err != nil {
log.Error("s.delRelatedMissions() error: %v", err)
}
if err = s.dao.SetAppealAssignState(c, ids, model.AssignStateNotDispatch); err != nil {
log.Error("s.dao.SetAppealAssignState(%v,%d) error(%v)", ids, model.AssignStateNotDispatch, err)
}
return
}
// 释放用户未评价反馈
func (s *Service) releaseExpireproc() {
for {
for _, attr := range s.businessAttr {
var (
c = context.TODO()
err error
)
if attr.DealType != model.PDealType {
continue
}
time.Sleep(1 * time.Minute)
cond := model.AppealSearchCond{
Fields: []string{"id", "mid"},
Bid: []int{attr.Bid},
TTimeTo: time.Now().AddDate(0, 0, -3).Format("2006-01-02 15:04:05"),
TransferState: []int8{model.TransferStatePendingSystemReply, model.TransferStateAdminReplyReaded, model.TransferStateAdminReplyNotReaded},
PS: 50,
PN: 1,
Order: "id",
Sort: "desc",
}
var res *model.AppealSearchRes
if res, err = s.dao.SearchAppeal(c, cond); err != nil {
log.Error("d.SearchAppeal error(%+v)", cond)
continue
}
ids := make([]int64, 0, len(res.Result))
for _, r := range res.Result {
var e *model.Event
if e, err = s.dao.LastEvent(r.ID); err != nil {
log.Error("s.dao.LastEvent() id(%d) error:%v", r.ID, err)
continue
}
// 关闭最后一个对话为管理员回复的申诉
if e.Event == model.EventAdminReply {
ids = append(ids, r.ID)
}
}
if len(ids) == 0 {
continue
}
// 删除权重参数
if err = s.dao.DelUperInfo(c, ids); err != nil {
log.Error("s.dao.DelUperInfo(%v), error(%v)", ids, err)
continue
}
// todo delete single expire zset member
if err = s.dao.DelSingleExpire(c, attr.Bid, ids); err != nil {
log.Error("s.dao.DelSingleExpire(%d, %v), error(%v)", attr.Bid, ids, err)
continue
}
if err = s.dao.SetAppealTransferState(c, ids, model.TransferStateAutoClosedExpire); err != nil {
log.Error("s.dao.SetAppealTransferState() ids(%v) transferstate(%d) error(%v)", ids, model.TransferStateAutoClosedExpire, err)
continue
}
log.Info("apids (%v) are expire user not set degree", ids)
}
}
}
// 进任务池
func (s *Service) enterPoolproc() {
for {
errGroup := errgroup.Group{}
for _, attr := range s.businessAttr {
if attr.DealType != model.PDealType {
continue
}
time.Sleep(1 * time.Second)
cond := model.AppealSearchCond{
Fields: []string{"id"},
Bid: []int{attr.Bid},
AssignState: []int8{model.AssignStateNotDispatch},
AuditState: []int8{model.AuditStateInvalid},
TransferState: []int8{model.TransferStatePendingSystemReply, model.TransferStatePendingSystemNotReply},
PS: 99,
PN: 1,
Order: "id",
Sort: "desc",
}
errGroup.Go(func(ctx context.Context) error {
return s.enterPool(ctx, cond)
})
}
errGroup.Wait()
}
}
func (s *Service) enterPool(c context.Context, cond model.AppealSearchCond) (err error) {
var res *model.AppealSearchRes
if res, err = s.dao.SearchAppeal(c, cond); err != nil {
log.Error("s.dao.SearchAppeal error(%+v)", cond)
return
}
ids := make([]int64, len(res.Result))
for _, r := range res.Result {
ids = append(ids, r.ID)
}
var appeals []*model.Appeal
if appeals, err = s.dao.Appeals(c, ids); err != nil {
log.Error("s.dao.Appeals(%v) error(%v)", ids, err)
return
}
ApIDMap := make(map[int64]int64) //map[ap_id]weight
ApIDs := make([]int64, 0)
// check state
for _, ap := range appeals {
if ap.AssignState == model.AssignStateNotDispatch && ap.AuditState == model.AuditStateInvalid && ap.TransferState == model.TransferStatePendingSystemReply {
ApIDMap[ap.ApID] = ap.Weight
ApIDs = append(ApIDs, ap.ApID)
}
}
if len(ApIDs) == 0 {
log.Warn("bid(%v) not found apids after check db should enter pool!", cond.Bid)
return
}
log.Info("bid(%v) apids(%v) ApIDMap(%v) should set into mission pool", cond.Bid, ApIDs, ApIDMap)
if err = s.dao.SetAppealAssignState(c, ApIDs, model.AssignStatePushed); err != nil {
log.Error("s.dao.SetAppealAssignState(%v) err(%v)", ApIDs, err)
return
}
//set sorted set
if err = s.dao.SetWeightSortedSet(c, cond.Bid[0], ApIDMap); err != nil {
log.Error("s.dao.SetWeightSortedSet() error(%v)", err)
}
return
}
// 刷新权重值 每3分钟刷新一次
func (s *Service) refreshWeightproc() {
errGroup := errgroup.Group{}
for {
time.Sleep(3 * time.Second) // todo 3 min
for _, attr := range s.businessAttr {
if attr.DealType != model.PDealType {
continue
}
time.Sleep(1 * time.Second)
cond := model.AppealSearchCond{
Bid: []int{attr.Bid},
Fields: []string{"id", "mid", "weight"},
AuditState: []int8{model.AuditStateInvalid},
TransferState: []int8{model.TransferStatePendingSystemReply},
PS: 100,
PN: 1,
Order: "id",
Sort: "desc",
}
errGroup.Go(func(ctx context.Context) error {
time.Sleep(3 * time.Second)
return s.refreshWeight(ctx, cond)
})
}
errGroup.Wait()
}
}
func (s *Service) refreshWeight(c context.Context, cond model.AppealSearchCond) (err error) {
var res *model.AppealSearchRes
if res, err = s.dao.SearchAppeal(c, cond); err != nil {
log.Error("d.SearchAppeal error(%+v)", cond)
return
}
appeals := make([]*model.Appeal, 0, len(res.Result))
apIDs := make([]int64, 0, len(res.Result))
newWeight := make(map[int64]int64, len(res.Result))
newWeightInSortedSet := make(map[int64]int64, len(res.Result))
for _, ap := range res.Result {
appeals = append(appeals, &model.Appeal{
ApID: ap.ID,
Mid: ap.Mid,
Weight: ap.Weight,
})
apIDs = append(apIDs, ap.ID)
}
if len(appeals) == 0 {
log.Warn("no appeal is in feedback")
return
}
var params []int64
if params, err = s.dao.UperInfoCache(c, apIDs); err != nil { // 读用户维度的权重参数
log.Error("s.dao.UperInfoCache(%v) error(%v)", apIDs, err)
return
}
// fixme cache miss
if len(params) != len(apIDs) {
log.Warn("len params not equre len mids")
return
}
for i, ap := range appeals {
p := params[i]
incr := s.calcWeight(ap, p)
newWeight[ap.ApID] = ap.Weight + incr
if ap.AssignState == model.AssignStatePushed { // should rewrite weight in db
newWeightInSortedSet[ap.ApID] = newWeight[ap.ApID]
}
}
log.Info("appeals in feedback weight(%+v) mids(%v)", newWeight, apIDs)
tx := s.dao.WriteORM.Begin()
if err = tx.Error; err != nil {
log.Error("s.dao.WriteORM.Begin() error(%v)", err)
return
}
if err = s.dao.TxSetWeight(tx, newWeight); err != nil {
log.Error("s.dao.SetWeight(%v) error(%v)", newWeight, err)
tx.Rollback()
return
}
if err = tx.Commit().Error; err != nil {
log.Error("tx.Commit() error:%v", err)
tx.Rollback()
return
}
// async write sorted set
if len(newWeightInSortedSet) == 0 {
return
}
_ = s.cache.Do(c, func(c context.Context) {
if err = s.dao.SetWeightSortedSet(c, cond.Bid[0], newWeightInSortedSet); err != nil {
log.Error("s.dao.SetWeightSortedSet() error(%v)", err)
}
log.Info("appeals in feedback sorted set bid(%d) weight(%+v)", cond.Bid[0], newWeightInSortedSet)
})
return
}
func (s *Service) delRelatedMissions(c context.Context, bid int, delIDs []int64) (err error) {
cond := model.AppealSearchCond{
Fields: []string{"id", "transfer_admin"},
IDs: delIDs,
Order: "id",
Sort: "asc",
PS: 100,
PN: 1,
}
var res *model.AppealSearchRes
if res, err = s.dao.SearchAppeal(c, cond); err != nil {
log.Error("s.dao.SearchAppeal() error:%v")
return
}
tadmin := make(map[int][]int64)
for _, r := range res.Result {
if _, ok := tadmin[r.TransferAdmin]; !ok {
tadmin[r.TransferAdmin] = make([]int64, 0)
}
tadmin[r.TransferAdmin] = append(tadmin[r.TransferAdmin], r.ID)
}
for uid, ids := range tadmin {
if err = s.dao.DelRelatedMissions(c, bid, uid, ids); err != nil {
log.Error("s.dao.DelRelatedMissions() bid(%d) uid(%d) ap_ids(%v) error:%v", bid, uid, ids, err)
}
time.Sleep(100 * time.Millisecond)
}
return
}
// calcWeight 计算权重值
func (s *Service) calcWeight(ap *model.Appeal, p int64) (incr int64) {
switch p { // 粉丝/特殊用户组维度
case 1:
incr += 8
case 2:
incr += 10
case 3:
incr += 12
case 4:
incr += 15
case 5:
incr += 18
default:
incr += 8
}
switch { // 时间维度
case time.Since(ap.CTime.Time()) < 3*time.Minute:
incr += 0
case time.Since(ap.CTime.Time()) >= 3*time.Minute && time.Since(ap.CTime.Time()) < 6*time.Minute:
incr += 3
case time.Since(ap.CTime.Time()) >= 6*time.Minute && time.Since(ap.CTime.Time()) < 9*time.Minute:
incr += 6
case time.Since(ap.CTime.Time()) >= 9*time.Minute && time.Since(ap.CTime.Time()) < 15*time.Minute:
incr += 9
case time.Since(ap.CTime.Time()) >= 15*time.Minute:
incr += 12
default:
incr += 0
}
return incr
}

View File

@@ -0,0 +1,59 @@
package service
import (
"context"
"strconv"
"time"
"go-common/app/job/main/workflow/model"
"go-common/library/log"
)
// taskExpireProc task expire.
func (s *Service) taskExpireproc(c context.Context, dealType int) {
var businessExpireMap = make(map[int64]int)
for _, v := range s.businessAttr {
if v.AssignType == 1 {
continue
}
businessExpireMap[v.ID] = v.ExpireTime
}
sParams := searchParams(c, dealType, model.ListAfter, s.businessAttr)
for {
var expireCids []int64
cLists, err := s.challByIDs(c, sParams)
if err != nil {
log.Error("s.challByIDs error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
if len(cLists) <= 0 {
time.Sleep(time.Second * 30)
continue
}
now := time.Now()
for k, cl := range cLists {
if cl.DispatchState != model.QueueState {
continue
}
dispatchTime := cl.DispatchTime.Format("2006-01-02 15:04:05")
expireTime := businessExpireMap[cl.Business]
m, _ := time.ParseDuration("-" + strconv.Itoa(expireTime) + "m")
if now.Add(m).Format("2006-01-02 15:04:05") > dispatchTime {
expireCids = append(expireCids, k)
}
}
if len(expireCids) > 0 {
log.Info("expire cids is %v", expireCids)
assignAdminid := int64(0)
newDispatchState := s.dispatchState(c, dealType, model.ListAfter, cLists[expireCids[0]].DispatchState)
err := s.dao.UpDispatchStateAdminIDByIds(c, expireCids, newDispatchState, assignAdminid)
if err != nil {
log.Error("s.dao.UpDispatchStateAdminIDByIds error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
}
time.Sleep(time.Second * 30)
}
}

View File

@@ -0,0 +1,232 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/admin/main/workflow/model/param"
"go-common/app/job/main/workflow/model"
"go-common/library/database/elastic"
"go-common/library/ecode"
"go-common/library/log"
)
const (
// LOGAPPID audit log appid .
LOGAPPID = "log_audit"
// LOGINDEX .
LOGINDEX = "log_audit_11_all"
// GROUPAPPID .
GROUPAPPID = "workflow_group_common"
// GROUPINDEX .
GROUPINDEX = "workflow_group_common"
// CHALLAPPID .
CHALLAPPID = "workflow_chall_common"
// CHALLINDEX .
CHALLINDEX = "workflow_chall_common"
// BUSINESS .
BUSINESS = 1
// MC .
MC = "1_15_1"
)
// notifyState .
var notifyState = []int64{0, 2}
// notifyproc .
func (s *Service) notifyproc(c context.Context) {
for {
if err := s.sendMessage(c); err != nil {
log.Error("s.sendMessage type(%d) error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
time.Sleep(time.Second * 60)
}
}
// SendMessage .
func (s *Service) sendMessage(c context.Context) (err error) {
var (
group []*model.GroupRes
chall map[int64][]*model.ChallRes
gids []int64
)
if group, err = s.NotNotifyGroupSearch(c); err != nil {
log.Error("s.NotNotifyGroupSearch error(%v)", err)
return
}
if len(group) <= 0 {
log.Info("group search length is 0")
return
}
for _, g := range group {
gids = append(gids, g.ID)
}
if chall, err = s.NotNotifyChallSearch(c, gids); err != nil {
log.Error("s.NotNotifyChallSearch error(%v)", err)
return
}
if len(chall) <= 0 {
log.Info("chall search length is 0")
return
}
for _, g := range group {
mids := []int64{}
ok := false
var chs []*model.ChallRes
if chs, ok = chall[g.ID]; !ok {
log.Error("gid(%d) in group but not in chall", g.ID)
continue
}
for _, ch := range chs {
mids = append(mids, ch.MID)
}
if len(mids) <= 0 {
log.Error("gid(%d) with mid in chall is empty", g.ID)
continue
}
param := &param.MessageParam{
Type: "json",
Source: 1,
DataType: 4,
MC: MC,
Title: "您的投诉已收到",
Context: fmt.Sprintf("您对稿件av%d的举报我们已经收到。感谢您对 bilibili 社区秩序的维护,哔哩哔哩 (゜-゜)つロ 干杯~ ", g.OID),
MidList: mids,
}
log.Info("send message param(%+v)", param)
if err = s.dao.SendMessage(c, chs, param); err != nil {
log.Error("s.dao.SendMessage error(%v)", err)
}
}
return
}
// NotNotifyGroupSearch .
func (s *Service) NotNotifyGroupSearch(c context.Context) (result []*model.GroupRes, err error) {
var (
pn = 1
ps = 1000
tempRes *model.SearchGroup
)
frontTenMin, _ := time.ParseDuration("-10m")
frontTwelveMin, _ := time.ParseDuration("-12m")
frontTenMinFormat := time.Now().Add(frontTenMin).Format("2006-01-02 15:04:05")
frontTwelveMinFormat := time.Now().Add(frontTwelveMin).Format("2006-01-02 15:04:05")
e := elastic.NewElastic(nil)
r := e.NewRequest(GROUPAPPID).Index(GROUPINDEX).Fields("id", "oid").
WhereEq("business", BUSINESS).
WhereIn("state", notifyState).
WhereRange("lasttime", frontTwelveMinFormat, frontTenMinFormat, elastic.RangeScopeLoRo).
Pn(pn).
Ps(ps)
if err = r.Scan(context.Background(), &tempRes); err != nil {
log.Error("elastic search group Scan error(%v)", err)
return
}
log.Info("groupparams is(%v)", r.Params())
res := tempRes.Result
if len(res) <= 0 {
return
}
// search audit log
var logGids map[int64][]*model.LogRes
if logGids, err = s.searchAuditLog(c, res); err != nil {
log.Error("s.searchAuditLog error(%v)", err)
return
}
for _, r := range res {
if _, ok := logGids[r.OID]; !ok {
result = append(result, r)
}
}
return
}
// searchAuditLog .
func (s *Service) searchAuditLog(c context.Context, grp []*model.GroupRes) (logGids map[int64][]*model.LogRes, err error) {
pn := 1
ps := 1000
oids := []int64{}
logGids = make(map[int64][]*model.LogRes)
for _, g := range grp {
oids = append(oids, g.OID)
}
e := elastic.NewElastic(nil)
for {
var res *model.AuditLog
r := e.NewRequest(LOGAPPID).Index(LOGINDEX).Fields("int_1", "oid").
WhereIn("oid", oids).
WhereEq("type", 2).
WhereEq("business", 11).
WhereEq("action", "notify_users_received").
Pn(pn).
Ps(ps)
if err = r.Scan(context.Background(), res); err != nil {
log.Error("elastic search audit log Scan error(%v)", err)
return
}
if res == nil {
time.Sleep(time.Second * 3)
continue
}
if res.Page.Total > 10000 {
log.Error("elastic search audit log result too long")
err = ecode.ServerErr
return
}
log.Info("auditlogparams is(%v)", r.Params())
logRes := res.Result
for _, lg := range logRes {
logGids[lg.Oid] = append(logGids[lg.Oid], lg)
}
if len(res.Result) < ps {
break
}
pn++
}
return
}
// NotNotifyChallSearch .
func (s *Service) NotNotifyChallSearch(c context.Context, gids []int64) (chall map[int64][]*model.ChallRes, err error) {
var (
pn = 1
ps = 1000
)
if len(gids) <= 0 {
return
}
chall = make(map[int64][]*model.ChallRes)
frontTenMin, _ := time.ParseDuration("-10m")
frontTwelveMin, _ := time.ParseDuration("-12m")
frontTenMinFormat := time.Now().Add(frontTenMin).Format("2006-01-02 15:04:05")
frontTwelveMinFormat := time.Now().Add(frontTwelveMin).Format("2006-01-02 15:04:05")
e := elastic.NewElastic(nil)
for {
res := &model.SearchChall{}
r := e.NewRequest(CHALLAPPID).Index(CHALLINDEX).Fields([]string{"id", "gid", "mid", "oid"}...).
WhereEq("business", BUSINESS).
WhereEq("state", 0).
WhereIn("gid", gids).
WhereRange("ctime", frontTwelveMinFormat, frontTenMinFormat, elastic.RangeScopeLoRo).
Pn(pn).
Ps(ps)
if err = r.Scan(context.Background(), &res); err != nil {
log.Error("elastic search chall Scan error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
log.Info("challparams is(%v)", r.Params())
for _, r := range res.Result {
chall[r.GID] = append(chall[r.GID], r)
}
if len(res.Result) < ps {
break
}
pn++
}
return
}

View File

@@ -0,0 +1,130 @@
package service
import (
"context"
"strings"
"time"
"go-common/app/job/main/workflow/model"
"go-common/library/log"
)
const (
_wfKeyPrefix = "wf_"
_feedbackDealType = 1
)
// queueProc .
func (s *Service) queueproc(c context.Context, dealType int) {
for {
var (
key string
listMap = make(map[string][]int64)
)
sParams := searchParams(c, dealType, model.ListBefore, s.businessAttr)
cLists, err := s.challByIDs(c, sParams)
if err != nil {
log.Error("s.challByIDs error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
if len(cLists) > 0 {
for _, cList := range cLists {
if cList.DispatchState != model.QueueState {
continue
}
now := time.Now().Format("2006-01-02 15:04:05")
log.Info("current cid(%d) dispatch_state is (%d) time is (%s)", cList.ID, cList.DispatchState, now)
key = genKey(c, cList.Business, dealType)
listMap[key] = append(listMap[key], cList.ID)
}
for key, list := range listMap {
newDispatchState := s.dispatchState(c, dealType, model.ListBefore, cLists[list[0]].DispatchState)
err := s.dao.UpDispatchStateByIDs(c, list, newDispatchState)
if err != nil {
log.Error("s.dao.UpDispatchStateByIDs error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
now := time.Now().Format("2006-01-02 15:04:05")
log.Info("this cids(%v) change dispatch_state to (%d) time is (%s)", list, newDispatchState, now)
err = s.dao.SetList(c, key, list)
if err != nil {
log.Error("s.dao.SetList error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
}
}
time.Sleep(time.Second * 15)
}
}
// repairListProc .
func (s *Service) repairQueueproc(c context.Context, dealType int) {
s.setCrash(c)
for {
time.Sleep(time.Second * 30)
exist, err := s.dao.IsCrash(c)
if err != nil {
log.Error("s.dao.ExistKey error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
if exist {
continue
}
var keySlice []string
for _, attr := range s.businessAttr {
var key string
if attr.AssignType == model.SysAssignType {
continue
}
if dealType == model.FDealType {
if dealType == attr.DealType {
key = genKey(c, attr.ID, dealType)
}
} else if dealType == model.ADealType {
key = genKey(c, attr.ID, dealType)
}
keySlice = append(keySlice, key)
}
sParams := searchParams(c, dealType, model.ListIng, s.businessAttr)
for _, key := range keySlice {
var cids []int64
sParams.Business = strings.Split(key, "_")[1]
searchRes, err := s.dao.SearchChall(c, sParams)
if err != nil {
log.Error("s.dao.SearchChall error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
searchDataRes := searchRes.Result
if len(searchDataRes) > 0 {
for _, r := range searchDataRes {
cids = append(cids, r.ID)
}
err := s.dao.SetList(c, key, cids)
if err != nil {
log.Error("s.dao.SetList error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
}
}
s.setCrash(c)
}
}
// SetConstKey .
func (s *Service) setCrash(c context.Context) {
for {
if err := s.dao.SetCrash(c); err != nil {
log.Error("s.dao.SetString error(%v)", err)
time.Sleep(time.Second * 3)
continue
}
break
}
}

View File

@@ -0,0 +1,70 @@
package service
import (
"context"
"sync"
"go-common/app/job/main/workflow/conf"
"go-common/app/job/main/workflow/dao"
"go-common/app/job/main/workflow/model"
"go-common/library/sync/pipeline/fanout"
)
// Service struct of service.
type Service struct {
c *conf.Config
dao *dao.Dao
wg *sync.WaitGroup
closeCh chan struct{}
businessAttr []*model.BusinessAttr
// cache
cache *fanout.Fanout
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
wg: &sync.WaitGroup{},
closeCh: make(chan struct{}),
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
}
var err error
if s.businessAttr, err = s.dao.BusinessAttr(context.Background()); err != nil {
panic(err)
}
//s.wg.Add(1)
//go s.expireproc(context.Background())
go s.queueproc(context.Background(), _feedbackDealType)
go s.taskExpireproc(context.Background(), _feedbackDealType)
go s.repairQueueproc(context.Background(), _feedbackDealType)
// push
go s.notifyproc(context.Background())
// 单条申诉过期
go s.singleExpireproc()
// 整体申诉过期
go s.overallExpireproc()
// 释放用户未评价反馈
go s.releaseExpireproc()
// 刷新权重值
go s.refreshWeightproc()
// 进任务池
go s.enterPoolproc()
return
}
// Ping check service health.
func (s *Service) Ping(c context.Context) error {
return s.dao.Ping(c)
}
// Close related backend.
func (s *Service) Close() (err error) {
err = s.dao.Close()
close(s.closeCh)
s.wg.Wait()
return
}

View File

@@ -0,0 +1,44 @@
package service
import (
"context"
"flag"
"path/filepath"
"testing"
"go-common/app/job/main/workflow/conf"
. "github.com/smartystreets/goconvey/convey"
)
func WithService(f func(s *Service)) func() {
return func() {
dir, _ := filepath.Abs("../goconvey.toml")
flag.Set("conf", dir)
conf.Init()
s := New(conf.Conf)
f(s)
}
}
func Test_queueproc(t *testing.T) {
var (
c = context.TODO()
dealType = 1
)
Convey("queueproc", t, WithService(func(s *Service) {
s.queueproc(c, dealType)
So(nil, ShouldBeNil)
}))
}
func Test_taskExpireproc(t *testing.T) {
var (
c = context.TODO()
dealType = 1
)
Convey("taskExpireproc", t, WithService(func(s *Service) {
s.taskExpireproc(c, dealType)
So(nil, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,107 @@
package service
import (
"context"
"strconv"
"strings"
"time"
"go-common/app/job/main/workflow/model"
srvmodel "go-common/app/service/main/workflow/model"
"go-common/library/log"
)
// searchParams .
func searchParams(c context.Context, dealType, listState int, busAttr []*model.BusinessAttr) (params *model.SearchParams) {
var businessArr []string
params = &model.SearchParams{}
if listState == model.ListBefore {
params.AssigneeAdminIDs = "0"
params.AssigneeAdminIDsNot = ""
switch dealType {
case model.FDealType:
params.States = model.FListBeforeStates
params.BusinessStates = model.FListBeforeBusinessStates
params.MtimeTo = time.Now().Add(-time.Minute * 1).Format("2006-01-02 15:04:05")
case model.ADealType:
params.States = model.AListBeforeStates
}
} else if listState == model.ListAfter {
params.AssigneeAdminIDs = ""
params.AssigneeAdminIDsNot = "0"
switch dealType {
case model.FDealType:
params.States = model.FListAfterStates
params.BusinessStates = model.FListAfterBusinessStates
case model.ADealType:
params.States = model.AListAfterStates
}
} else if listState == model.ListIng {
params.AssigneeAdminIDs = ""
params.AssigneeAdminIDsNot = ""
switch dealType {
case model.FDealType:
params.States = model.FListAfterStates
params.BusinessStates = model.FListAfterBusinessStates
case model.ADealType:
params.States = model.AListAfterStates
}
}
for _, attr := range busAttr {
if attr.AssignType == model.SysAssignType {
continue
}
if dealType == model.ADealType {
businessArr = append(businessArr, strconv.FormatInt(attr.ID, 10))
} else {
if attr.DealType == dealType {
businessArr = append(businessArr, strconv.FormatInt(attr.ID, 10))
}
}
}
params.Business = strings.Join(businessArr, ",")
return
}
// challByIDs .
func (s *Service) challByIDs(c context.Context, params *model.SearchParams) (res map[int64]*model.Chall, err error) {
var cids []int64
searchRes, err := s.dao.SearchChall(c, params)
if err != nil {
log.Error("s.dao.SearchChall error(%v)", err)
return
}
searchDataRes := searchRes.Result
if len(searchDataRes) > 0 {
for _, r := range searchDataRes {
cids = append(cids, r.ID)
}
res, err = s.dao.ChallByIDs(c, cids)
}
return
}
// disPatchState .
func (s *Service) dispatchState(c context.Context, dealType, listState, oldDispatchState int) (newDispatchState int64) {
state := oldDispatchState & srvmodel.QueueState
if dealType == model.FDealType {
if listState == model.ListBefore {
newDispatchState, _ = strconv.ParseInt("f"+strconv.Itoa(state), 16, 64)
} else if listState == model.ListAfter {
newDispatchState, _ = strconv.ParseInt("1"+strconv.Itoa(state), 16, 64)
}
} else if dealType == model.ADealType {
if listState == model.ListBefore {
newDispatchState = int64(srvmodel.QueueState)
} else if listState == model.ListAfter {
newDispatchState = int64(srvmodel.QueueStateBefore)
}
}
return
}
// key .
func genKey(c context.Context, business int64, dealType int) (key string) {
key = _wfKeyPrefix + strconv.FormatInt(business, 10) + "_" + strconv.Itoa(dealType)
return
}