179 lines
4.1 KiB
Go
179 lines
4.1 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"sync"
|
||
"sync/atomic"
|
||
"time"
|
||
|
||
"go-common/app/job/main/push/conf"
|
||
"go-common/app/job/main/push/dao"
|
||
pushrpc "go-common/app/service/main/push/api/grpc/v1"
|
||
pushmdl "go-common/app/service/main/push/model"
|
||
"go-common/library/cache"
|
||
"go-common/library/conf/env"
|
||
"go-common/library/log"
|
||
"go-common/library/queue/databus"
|
||
)
|
||
|
||
const (
|
||
_max = 1024
|
||
_retry = 3
|
||
)
|
||
|
||
// Service .
|
||
type Service struct {
|
||
c *conf.Config
|
||
dao *dao.Dao
|
||
waiter sync.WaitGroup
|
||
addTaskWg sync.WaitGroup
|
||
cache *cache.Cache
|
||
pushRPC pushrpc.PushClient
|
||
reportSub *databus.Databus // consumer for new reports
|
||
callbackSub *databus.Databus // consumer for callback
|
||
reportCh chan []*pushmdl.Report
|
||
callbackCh chan []*pushmdl.Callback
|
||
addTaskCh chan *pushmdl.Task
|
||
reportCnt int64
|
||
callbackCnt int64
|
||
closedCnt int64
|
||
closed bool
|
||
}
|
||
|
||
// New creates a Service instance.
|
||
func New(c *conf.Config) (s *Service) {
|
||
s = &Service{
|
||
c: c,
|
||
dao: dao.New(c),
|
||
cache: cache.New(1, 102400),
|
||
reportSub: databus.New(c.ReportSub),
|
||
callbackSub: databus.New(c.CallbackSub),
|
||
reportCh: make(chan []*pushmdl.Report, 1024),
|
||
callbackCh: make(chan []*pushmdl.Callback, 1024),
|
||
addTaskCh: make(chan *pushmdl.Task, 10240),
|
||
}
|
||
var err error
|
||
if s.pushRPC, err = pushrpc.NewClient(c.PushRPC); err != nil {
|
||
panic(err)
|
||
}
|
||
if env.DeployEnv == env.DeployEnvProd {
|
||
go s.delInvalidReportsproc() // 主动删除无效token
|
||
}
|
||
for i := 0; i < s.c.Job.ReportShard; i++ {
|
||
s.waiter.Add(1)
|
||
go s.reportproc()
|
||
}
|
||
for i := 0; i < s.c.Job.CallbackShard; i++ {
|
||
s.waiter.Add(1)
|
||
go s.callbackproc()
|
||
}
|
||
if s.c.Job.PretreatTask {
|
||
for i := 0; i < s.c.Job.PretreatmentTaskShard; i++ {
|
||
s.waiter.Add(1)
|
||
go s.pretreatTaskproc() // 预处理任务,将任务转化成按平台分的token任务
|
||
}
|
||
}
|
||
s.addTaskWg.Add(1)
|
||
go s.addTaskproc()
|
||
s.waiter.Add(1)
|
||
go s.consumeReport()
|
||
s.waiter.Add(1)
|
||
go s.consumeCallback()
|
||
go s.checkConsumer()
|
||
// 删除过期的数据
|
||
go s.delCallbacksproc()
|
||
go s.delTasksproc()
|
||
// 定期更新token缓存
|
||
go s.refreshTokensproc()
|
||
// data platform
|
||
s.waiter.Add(1)
|
||
go s.dpQueryproc()
|
||
s.waiter.Add(1)
|
||
go s.dpFileproc()
|
||
return
|
||
}
|
||
|
||
// consumeReport consumes report.
|
||
func (s *Service) consumeReport() {
|
||
defer s.waiter.Done()
|
||
reports := make([]*pushmdl.Report, _max)
|
||
ticker := time.NewTicker(time.Duration(s.c.Job.ReportTicker))
|
||
for {
|
||
select {
|
||
case msg, ok := <-s.reportSub.Messages():
|
||
if !ok {
|
||
log.Info("databus: push-job report consumer exit!")
|
||
if len(reports) > 0 {
|
||
s.reportCh <- reports
|
||
}
|
||
if !atomic.CompareAndSwapInt64(&s.closedCnt, 0, 1) {
|
||
close(s.reportCh)
|
||
}
|
||
return
|
||
}
|
||
s.reportCnt++
|
||
msg.Commit()
|
||
m := &pushmdl.Report{}
|
||
if err := json.Unmarshal(msg.Value, m); err != nil {
|
||
log.Error("json.Unmarshal(%s) error(%v)", msg.Value, err)
|
||
dao.PromError("service:解析计数databus消息")
|
||
continue
|
||
}
|
||
log.Info("consumeReport key(%s) partition(%d) offset(%d) msg(%+v)", msg.Key, msg.Partition, msg.Offset, m)
|
||
reports = append(reports, m)
|
||
if len(reports) < _max {
|
||
continue
|
||
}
|
||
case <-ticker.C:
|
||
}
|
||
if len(reports) > 0 {
|
||
temp := make([]*pushmdl.Report, len(reports))
|
||
copy(temp, reports)
|
||
reports = []*pushmdl.Report{}
|
||
s.reportCh <- temp
|
||
}
|
||
}
|
||
}
|
||
|
||
// checkConsumer checks consumer state.
|
||
func (s *Service) checkConsumer() {
|
||
if env.DeployEnv != env.DeployEnvProd {
|
||
return
|
||
}
|
||
var c1, c2 int64
|
||
for {
|
||
time.Sleep(5 * time.Minute)
|
||
|
||
if s.reportCnt-c1 == 0 {
|
||
msg := "push-job report did not consume within 5 minute"
|
||
s.dao.SendWechat(msg)
|
||
log.Warn(msg)
|
||
}
|
||
c1 = s.reportCnt
|
||
|
||
if s.callbackCnt-c2 == 0 {
|
||
msg := "push-job callback did not consume within 5 minute"
|
||
s.dao.SendWechat(msg)
|
||
log.Warn(msg)
|
||
}
|
||
c2 = s.callbackCnt
|
||
}
|
||
}
|
||
|
||
// Ping reports the heath of services.
|
||
func (s *Service) Ping(c context.Context) (err error) {
|
||
return s.dao.Ping(c)
|
||
}
|
||
|
||
// Close releases resources which owned by the Service instance.
|
||
func (s *Service) Close() {
|
||
s.closed = true
|
||
s.reportSub.Close()
|
||
s.callbackSub.Close()
|
||
s.dao.Close()
|
||
s.waiter.Wait()
|
||
close(s.addTaskCh)
|
||
s.addTaskWg.Wait()
|
||
}
|