go-common/app/interface/main/history/service/service.go
2019-04-22 18:49:16 +08:00

240 lines
5.1 KiB
Go

package service
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/history/conf"
"go-common/app/interface/main/history/dao/history"
"go-common/app/interface/main/history/dao/toview"
"go-common/app/interface/main/history/model"
arcrpc "go-common/app/service/main/archive/api/gorpc"
favrpc "go-common/app/service/main/favorite/api/gorpc"
hisrpc "go-common/app/service/main/history/api/grpc"
"go-common/library/log"
"go-common/library/queue/databus/report"
"go-common/library/sync/pipeline/fanout"
)
type playPro struct {
Type int8 `json:"type"`
SubType int8 `json:"sub_type"`
Mid int64 `json:"mid"`
Sid int64 `json:"sid"`
Epid int64 `json:"epid"`
Cid int64 `json:"cid"`
Progress int64 `json:"progress"`
IP string `json:"ip"`
Ts int64 `json:"ts"`
RealTime int64 `json:"realtime"`
}
// Service is history service.
type Service struct {
conf *conf.Config
historyDao *history.Dao
toviewDao *toview.Dao
delChan *fanout.Fanout
mergeChan chan *model.Merge
msgs chan *playPro
proChan chan *model.History
serviceChan chan func()
favRPC *favrpc.Service
arcRPC *arcrpc.Service2
hisRPC hisrpc.HistoryClient
cache *fanout.Fanout
toviewCache *fanout.Fanout
midMap map[int64]bool
}
// New new a History service.
func New(c *conf.Config) (s *Service) {
s = &Service{
conf: c,
historyDao: history.New(c),
toviewDao: toview.New(c),
mergeChan: make(chan *model.Merge, 1024),
msgs: make(chan *playPro, 1024),
proChan: make(chan *model.History, 1024),
serviceChan: make(chan func(), 10240),
delChan: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
arcRPC: arcrpc.New2(c.RPCClient2.Archive),
favRPC: favrpc.New2(c.RPCClient2.Favorite),
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
toviewCache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
midMap: make(map[int64]bool),
}
for _, v := range s.conf.History.Mids {
s.midMap[v] = true
}
var err error
if s.hisRPC, err = hisrpc.NewClient(c.RPCClient2.History); err != nil {
panic(err)
}
go s.playProproc()
go s.mergeproc()
go s.proPubproc()
for i := 0; i < s.conf.History.ConsumeSize; i++ {
go s.serviceproc()
}
return
}
func (s *Service) addMerge(mid, now int64) {
select {
case s.mergeChan <- &model.Merge{Mid: mid, Now: now}:
default:
log.Warn("mergeChan chan is full")
}
}
func (s *Service) addPlayPro(p *playPro) {
select {
case s.msgs <- p:
default:
log.Warn("s.msgs chan is full")
}
}
func (s *Service) addProPub(p *model.History) {
select {
case s.proChan <- p:
default:
log.Warn("s.proChan chan is full")
}
}
func (s *Service) mergeproc() {
var (
m *model.Merge
ticker = time.NewTicker(time.Duration(s.conf.History.Ticker))
mergeMap = make(map[int64]int64)
)
for {
select {
case m = <-s.mergeChan:
if m == nil {
s.merge(mergeMap)
return
}
if _, ok := mergeMap[m.Mid]; !ok {
mergeMap[m.Mid] = m.Now
}
if len(mergeMap) < s.conf.History.Page {
continue
}
case <-ticker.C:
}
s.merge(mergeMap)
mergeMap = make(map[int64]int64)
}
}
// playProproc send history to databus.
func (s *Service) playProproc() {
var (
msg *playPro
ms []*playPro
ticker = time.NewTicker(time.Second)
)
for {
select {
case msg = <-s.msgs:
if msg == nil {
if len(ms) > 0 {
s.pushPlayPro(ms)
}
return
}
ms = append(ms, msg)
if len(ms) < 100 {
continue
}
case <-ticker.C:
}
if len(ms) == 0 {
continue
}
s.pushPlayPro(ms)
ms = make([]*playPro, 0, 100)
}
}
func (s *Service) pushPlayPro(ms []*playPro) {
key := fmt.Sprintf("%d%d", ms[0].Mid, ms[0].Sid)
for j := 0; j < 3; j++ {
if err := s.historyDao.PlayPro(context.Background(), key, ms); err == nil {
return
}
}
}
// proPubroc send history to databus.
func (s *Service) proPubproc() {
for {
msg := <-s.proChan
if msg == nil {
return
}
s.proPub(msg)
}
}
func (s *Service) proPub(msg *model.History) {
key := fmt.Sprintf("%d%d", msg.Mid, msg.Aid)
for j := 0; j < 3; j++ {
if err := s.historyDao.ProPub(context.Background(), key, msg); err == nil {
break
}
}
}
func (s *Service) userActionLog(mid int64, action string) {
report.User(&report.UserInfo{
Mid: mid,
Business: model.HistoryLog,
Action: action,
Ctime: time.Now(),
})
}
func (s *Service) migration(mid int64) bool {
if !s.conf.History.Migration || mid == 0 {
return false
}
if _, ok := s.midMap[mid]; ok {
return true
}
if s.conf.History.Rate != 0 && mid%s.conf.History.Rate == 0 {
return true
}
return false
}
// Ping ping service.
// +wd:ignore
func (s *Service) Ping(c context.Context) (err error) {
if s.historyDao != nil {
err = s.historyDao.Ping(c)
}
if s.toviewDao != nil {
err = s.toviewDao.Ping(c)
}
return
}
// Close close resource.
// +wd:ignore
func (s *Service) Close() {
s.mergeChan <- nil
s.msgs <- nil
s.proChan <- nil
if s.historyDao != nil {
s.historyDao.Close()
}
if s.toviewDao != nil {
s.toviewDao.Close()
}
}