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,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["service_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/archive-shjd/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"cache.go",
"retry.go",
"service.go",
"stat.go",
],
importpath = "go-common/app/job/main/archive-shjd/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/archive-shjd/conf:go_default_library",
"//app/job/main/archive-shjd/model:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//library/cache/redis:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/pkg/errors: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"],
)

View File

@@ -0,0 +1,138 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/archive-shjd/model"
accmdl "go-common/app/service/main/account/model"
"go-common/app/service/main/archive/api"
arcmdl "go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/queue/databus"
)
const (
_actForUname = "updateUname"
_actForFace = "updateFace"
_actForAdmin = "updateByAdmin"
)
func (s *Service) accountNotifyproc() {
defer s.waiter.Done()
var msgs = s.accountNotify.Messages()
for {
var (
msg *databus.Message
ok bool
err error
c = context.TODO()
)
if msg, ok = <-msgs; !ok {
log.Error("s.cachesub.messages closed")
return
}
msg.Commit()
m := &model.AccountNotify{}
if err = json.Unmarshal(msg.Value, m); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", msg.Value, err)
continue
}
log.Info("accountNotify got key(%s) value(%s)", msg.Key, msg.Value)
if m.Action != _actForAdmin && m.Action != _actForFace && m.Action != _actForUname {
log.Warn("accountNotify skip action(%s) values(%s)", m.Action, msg.Value)
continue
}
var count int
if count, err = s.arcRPCs["group1"].UpCount2(c, &arcmdl.ArgUpCount2{Mid: m.Mid}); err != nil {
log.Error("s.arcRPC.UpCount2(%d) error(%v)", m.Mid, err)
continue
}
if count == 0 {
log.Info("accountNotify mid(%d) passed(%d)", m.Mid, count)
continue
}
if m.Action == _actForAdmin {
// check uname or face is updated
var am []*api.Arc
if am, err = s.arcRPCs["group1"].UpArcs3(c, &arcmdl.ArgUpArcs2{Mid: m.Mid, Ps: 2, Pn: 1}); err != nil {
if ecode.Cause(err).Equal(ecode.NothingFound) {
err = nil
log.Info("accountNotify mid(%d) no passed archive", m.Mid)
continue
}
log.Error("accountNotify mid(%d) error(%v)", m.Mid, err)
continue
}
if len(am) == 0 {
log.Info("accountNotify mid(%d) no passed archive", m.Mid)
continue
}
var info *accmdl.Info
if info, err = s.accRPC.Info3(c, &accmdl.ArgMid{Mid: m.Mid}); err != nil {
log.Error("accountNotify accRPC.info3(%d) error(%v)", m.Mid, err)
continue
}
if info.Name == am[0].Author.Name && info.Face == am[0].Author.Face {
log.Info("accountNotify face(%s) name(%s) not change", info.Face, info.Name)
continue
}
}
s.notifyMu.Lock()
s.notifyMid[m.Mid] = struct{}{}
s.notifyMu.Unlock()
}
}
func (s *Service) clearMidCache() {
defer s.waiter.Done()
for {
time.Sleep(5 * time.Second)
s.notifyMu.Lock()
mids := s.notifyMid
s.notifyMid = make(map[int64]struct{})
s.notifyMu.Unlock()
log.Info("start clearMidCache mids(%d)", len(mids))
for mid := range mids {
s.updateUpperCache(context.TODO(), mid)
}
log.Info("finish clearMidCache mids(%d)", len(mids))
if s.close && len(s.notifyMid) == 0 {
return
}
}
}
func (s *Service) updateUpperCache(c context.Context, mid int64) (err error) {
failedCnt := 0
for k, rpc := range s.arcRPCs {
pn := 1
for {
var arcs []*api.Arc
if arcs, err = rpc.UpArcs3(c, &arcmdl.ArgUpArcs2{Mid: mid, Pn: pn}); err != nil {
log.Error("rpc(%s) UpArcs3(%d) error(%v)", k, mid, err)
break
}
pn++
if len(arcs) == 0 {
break
}
for _, arc := range arcs {
if err = rpc.ArcCache2(c, &arcmdl.ArgCache2{Aid: arc.Aid, Tp: arcmdl.CacheUpdate}); err != nil {
log.Error("s.arcRPC(%d).ArcCache2(%d, %s) mid(%d) error(%v)", k, arc.Aid, arcmdl.CacheUpdate, mid, err)
failedCnt++
continue
}
}
}
}
if failedCnt > 0 {
log.Error("accountNotify updateUpperCache mid(%d) failed(%d)", mid, failedCnt)
return
}
log.Info("accountNofity updateUpperCache mid(%d)", mid)
return
}

View File

@@ -0,0 +1,126 @@
package service
import (
"context"
"strconv"
"go-common/app/job/main/archive-shjd/model"
arcmdl "go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
// UpdateCache is
func (s *Service) UpdateCache(old *model.Archive, nw *model.Archive, action string) (err error) {
defer func() {
if err == nil {
s.notifyPub.Send(context.Background(), strconv.FormatInt(nw.AID, 10), &model.Notify{Table: _tableArchive, Nw: nw, Old: old, Action: action})
return
}
// retry
item := &model.RetryItem{
Old: old,
Nw: nw,
Tp: model.TypeForUpdateArchive,
Action: action,
}
if err1 := s.PushItem(context.TODO(), item); err1 != nil {
log.Error("s.PushItem(%+v) error(%+v)", item, err1)
return
}
}()
args := &arcmdl.ArgCache2{}
args.Aid = nw.AID
args.Tp = arcmdl.CacheUpdate
if old == nil {
// insert
if nw.State >= 0 {
args.Tp = arcmdl.CacheAdd
}
} else {
if nw.State >= 0 {
args.Tp = arcmdl.CacheAdd
} else {
args.Tp = arcmdl.CacheDelete
}
if nw.Mid != old.Mid {
args.OldMid = old.Mid
}
if old.TypeID != nw.TypeID {
fieldAgs := &arcmdl.ArgFieldCache2{Aid: nw.AID, TypeID: nw.TypeID, OldTypeID: old.TypeID}
for cluster, arc := range s.arcRPCs {
if err = arc.ArcFieldCache2(context.TODO(), fieldAgs); err != nil {
log.Error("s.arcRPC.ArcFieldCache2(%s, %+v) error(%+v)", cluster, fieldAgs, err)
return
}
}
}
}
for cluster, arc := range s.arcRPCs {
if err = arc.ArcCache2(context.TODO(), args); err != nil {
log.Error("s.arcRPC.ArcCache2(%s,%+v) error(%v)", cluster, args, err)
return
}
}
return
}
// UpdateVideoCache is
func (s *Service) UpdateVideoCache(aid, cid int64) (err error) {
defer func() {
if err == nil {
return
}
// retry
item := &model.RetryItem{
AID: aid,
CID: cid,
Tp: model.TypeForUpdateVideo,
}
if err1 := s.PushItem(context.TODO(), item); err1 != nil {
log.Error("s.PushItem(%+v) error(%+v)", item, err1)
return
}
}()
for cluster, arc := range s.arcRPCs {
if err = arc.UpVideo2(context.TODO(), &arcmdl.ArgVideo2{Aid: aid, Cid: cid}); err != nil {
if ecode.Cause(err).Equal(ecode.NothingFound) {
err = nil
return
}
err = errors.Wrapf(err, "s.arcRPC.UpVideo2 cluster(%s)", cluster)
}
}
return
}
// DelteVideoCache del video cache
func (s *Service) DelteVideoCache(aid, cid int64) (err error) {
defer func() {
if err == nil {
return
}
// retry
item := &model.RetryItem{
AID: aid,
CID: cid,
Tp: model.TypeForDelVideo,
}
if err1 := s.PushItem(context.TODO(), item); err1 != nil {
log.Error("s.PushItem(%+v) error(%+v)", item, err1)
return
}
}()
for cluster, arc := range s.arcRPCs {
if err = arc.DelVideo2(context.TODO(), &arcmdl.ArgVideo2{Aid: aid, Cid: cid}); err != nil {
if ecode.Cause(err).Equal(ecode.NothingFound) {
err = nil
return
}
err = errors.Wrapf(err, "s.arcRPC.VdelVideo2 cluster(%s)", cluster)
}
}
return
}

View File

@@ -0,0 +1,88 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/archive-shjd/model"
"go-common/library/cache/redis"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_retryList = "retry_list"
)
func (s *Service) retryconsumer() {
defer s.waiter.Done()
for {
if s.close {
log.Info("retryconsumer closed")
return
}
var (
c = context.TODO()
err error
item *model.RetryItem
)
if item, err = s.PopItem(c); err != nil {
log.Error("%+v")
time.Sleep(2 * time.Second)
continue
}
if item == nil {
time.Sleep(1 * time.Second)
continue
}
log.Info("get retry item(%+v)", item)
switch item.Tp {
case model.TypeForDelVideo:
s.DelteVideoCache(item.AID, item.CID)
case model.TypeForUpdateVideo:
s.UpdateVideoCache(item.AID, item.CID)
case model.TypeForUpdateArchive:
s.UpdateCache(item.Old, item.Nw, item.Action)
}
time.Sleep(10 * time.Millisecond)
}
}
// PushItem is
func (s *Service) PushItem(c context.Context, item *model.RetryItem) (err error) {
conn := s.rds.Get(c)
defer conn.Close()
bs, err := json.Marshal(item)
if err != nil {
err = errors.Wrap(err, "json.Marshal")
return
}
if _, err = conn.Do("RPUSH", _retryList, bs); err != nil {
err = errors.Wrap(err, "conn.Send(RPUSH)")
return
}
return
}
// PopItem is
func (s *Service) PopItem(c context.Context) (item *model.RetryItem, err error) {
conn := s.rds.Get(c)
defer conn.Close()
bs, err := redis.Bytes(conn.Do("LPOP", _retryList))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
err = errors.WithStack(err)
return
}
item = &model.RetryItem{}
if err = json.Unmarshal(bs, item); err != nil {
err = errors.WithStack(err)
return
}
return
}

View File

@@ -0,0 +1,222 @@
package service
import (
"context"
"encoding/json"
"sync"
"time"
"go-common/app/job/main/archive-shjd/conf"
"go-common/app/job/main/archive-shjd/model"
accrpc "go-common/app/service/main/account/rpc/client"
"go-common/app/service/main/archive/api"
arcrpc "go-common/app/service/main/archive/api/gorpc"
"go-common/library/cache/redis"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/pkg/errors"
)
const (
_tableArchive = "archive"
_tableVideo = "archive_video"
_actionInsert = "insert"
_actionUpdate = "update"
_actionDelete = "delete"
_sharding = 10
)
type lastTmStat struct {
last int64
stat *api.Stat
}
// Service service
type Service struct {
c *conf.Config
waiter sync.WaitGroup
canal *databus.Databus
canalChan chan *model.Message
subMap map[string]*databus.Databus
subView *databus.Databus
subDm *databus.Databus
subReply *databus.Databus
subFav *databus.Databus
subCoin *databus.Databus
subShare *databus.Databus
subRank *databus.Databus
subLike *databus.Databus
notifyPub *databus.Databus
accountNotify *databus.Databus
subStatCh []chan *model.StatMsg
arcRPCs map[string]*arcrpc.Service2
accRPC *accrpc.Service3
notifyMid map[int64]struct{}
notifyMu sync.Mutex
rds *redis.Pool
statSM []map[int64]*lastTmStat
close bool
}
// New is archive service implementation.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
canal: databus.New(c.Databus),
canalChan: make(chan *model.Message, 10240),
rds: redis.NewPool(c.Redis),
subMap: make(map[string]*databus.Databus),
// databus
subView: databus.New(c.ViewSub),
subDm: databus.New(c.DmSub),
subReply: databus.New(c.ReplySub),
subFav: databus.New(c.FavSub),
subCoin: databus.New(c.CoinSub),
subShare: databus.New(c.ShareSub),
subRank: databus.New(c.RankSub),
subLike: databus.New(c.LikeSub),
notifyPub: databus.New(c.NotifyPub),
accountNotify: databus.New(c.AccountNotify),
notifyMid: make(map[int64]struct{}, 10240),
accRPC: accrpc.New3(nil),
}
s.arcRPCs = make(map[string]*arcrpc.Service2)
for _, cc := range c.ArchiveRPCs {
s.arcRPCs[cc.Cluster] = arcrpc.New2(cc)
}
s.subMap[model.TypeForView] = s.subView
s.subMap[model.TypeForDm] = s.subDm
s.subMap[model.TypeForReply] = s.subReply
s.subMap[model.TypeForFav] = s.subFav
s.subMap[model.TypeForCoin] = s.subCoin
s.subMap[model.TypeForShare] = s.subShare
s.subMap[model.TypeForRank] = s.subRank
s.subMap[model.TypeForLike] = s.subLike
for i := 0; i < _sharding; i++ {
s.waiter.Add(1)
go s.canalChanproc()
s.subStatCh = append(s.subStatCh, make(chan *model.StatMsg, 10240))
s.statSM = append(s.statSM, map[int64]*lastTmStat{})
s.waiter.Add(1)
go s.statDealproc(i)
}
for k, d := range s.subMap {
s.waiter.Add(1)
go s.consumerproc(k, d)
}
s.waiter.Add(1)
go s.canalproc()
s.waiter.Add(1)
go s.retryconsumer()
s.waiter.Add(1)
go s.accountNotifyproc()
s.waiter.Add(1)
go s.clearMidCache()
return s
}
func (s *Service) canalChanproc() {
defer s.waiter.Done()
for {
m, ok := <-s.canalChan
if !ok {
log.Info("canalChanproc closed")
return
}
log.Info("got canal message table(%s) action(%s) old(%s) new(%s)", m.Table, m.Action, m.Old, m.New)
var err error
switch m.Table {
case _tableArchive:
var (
old *model.Archive
nw *model.Archive
)
switch m.Action {
case _actionInsert:
if err = json.Unmarshal(m.New, &nw); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", m.New, err)
continue
}
case _actionUpdate:
if err = json.Unmarshal(m.Old, &old); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", m.Old, err)
continue
}
if err = json.Unmarshal(m.New, &nw); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", m.New, err)
continue
}
default:
log.Warn("got unknow action(%s)", m.Action)
continue
}
s.UpdateCache(old, nw, m.Action)
case _tableVideo:
var video *model.Video
if err = json.Unmarshal(m.New, &video); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", m.New, err)
continue
}
switch m.Action {
case _actionInsert, _actionUpdate:
err = s.UpdateVideoCache(video.AID, video.CID)
case _actionDelete:
err = s.DelteVideoCache(video.AID, video.CID)
default:
bs, _ := json.Marshal(m)
log.Error("unknow action(%s) message(%s)", m.Action, bs)
}
if err != nil {
log.Error("%+v", err)
continue
}
default:
log.Warn("table(%s) skiped", m.Table)
}
}
}
func (s *Service) canalproc() {
defer s.waiter.Done()
msgs := s.canal.Messages()
for {
msg, ok := <-msgs
if !ok || s.close {
close(s.canalChan)
log.Info("s.closed databus canal")
return
}
var (
m = &model.Message{}
err error
)
msg.Commit()
log.Info("got message(%s)", msg.Value)
if err = json.Unmarshal(msg.Value, m); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", msg.Value, err)
continue
}
s.canalChan <- m
}
}
// Ping check status
func (s *Service) Ping() (err error) {
conn := s.rds.Get(context.TODO())
defer conn.Close()
if _, err = conn.Do("SET", "PING", "PONG"); err != nil {
err = errors.Wrap(err, "redis ping")
return
}
return
}
// Close is
func (s *Service) Close() (err error) {
s.close = true
time.Sleep(5 * time.Second)
s.canal.Close()
s.waiter.Wait()
return
}

View File

@@ -0,0 +1,46 @@
package service
import (
"flag"
"path/filepath"
"testing"
"go-common/app/job/main/archive-shjd/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
dir, _ := filepath.Abs("../cmd/archive-job-kisjd-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
}
func Test_Ping(t *testing.T) {
Convey("Ping", t, func() {
s.Ping()
})
}
func Test_DelteVideoCache(t *testing.T) {
Convey("DelteVideoCache", t, func() {
s.DelteVideoCache(1, 1)
})
}
func Test_UpdateVideoCache(t *testing.T) {
Convey("UpdateVideoCache", t, func() {
s.UpdateVideoCache(1, 1)
})
}
func Test_Close(t *testing.T) {
Convey("Close", t, func() {
s.Close()
})
}

View File

@@ -0,0 +1,123 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/archive-shjd/model"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/queue/databus"
)
// consumerproc consumer all topic
func (s *Service) consumerproc(k string, d *databus.Databus) {
defer s.waiter.Done()
var msgs = d.Messages()
for {
var (
err error
ok bool
msg *databus.Message
now = time.Now().Unix()
)
msg, ok = <-msgs
if !ok || s.close {
log.Info("databus(%s) consumer exit", k)
return
}
msg.Commit()
var ms = &model.StatCount{}
if err = json.Unmarshal(msg.Value, ms); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(msg.Value), err)
continue
}
if ms.Aid <= 0 || (ms.Type != "archive" && ms.Type != "archive_his") {
log.Warn("message(%s) error", msg.Value)
continue
}
if now-ms.TimeStamp > 1800 {
log.Warn("topic(%s) message(%s) too early", msg.Topic, msg.Value)
continue
}
stat := &model.StatMsg{Aid: ms.Aid, Type: k, Ts: ms.TimeStamp}
switch k {
case model.TypeForView:
stat.Click = ms.Count
case model.TypeForDm:
stat.DM = ms.Count
case model.TypeForReply:
stat.Reply = ms.Count
case model.TypeForFav:
stat.Fav = ms.Count
case model.TypeForCoin:
stat.Coin = ms.Count
case model.TypeForShare:
stat.Share = ms.Count
case model.TypeForRank:
stat.HisRank = ms.Count
case model.TypeForLike:
stat.Like = ms.Count
default:
log.Error("unknow type(%s) message(%s)", k, msg.Value)
continue
}
s.subStatCh[stat.Aid%_sharding] <- stat
log.Info("got message(%+v)", stat)
}
}
func (s *Service) statDealproc(i int) {
defer s.waiter.Done()
var (
ch = s.subStatCh[i]
sm = s.statSM[i]
c = context.TODO()
ls *lastTmStat
err error
)
for {
ms, ok := <-ch
if !ok {
log.Info("statDealproc(%d) quit", i)
return
}
// get stat
if ls, ok = sm[ms.Aid]; !ok {
var stat *api.Stat
for _, arc := range s.arcRPCs {
if stat, err = arc.Stat3(c, &archive.ArgAid2{Aid: ms.Aid}); err == nil {
break
}
}
if stat == nil {
log.Error("stat(%d) is nill", ms.Aid)
continue
}
ls = &lastTmStat{}
ls.stat = stat
sm[ms.Aid] = ls
}
model.Merge(ms, ls.stat)
// update cache
st := &api.Stat{
Aid: ls.stat.Aid,
View: ls.stat.View,
Danmaku: ls.stat.Danmaku,
Reply: ls.stat.Reply,
Fav: ls.stat.Fav,
Coin: ls.stat.Coin,
Share: ls.stat.Share,
NowRank: ls.stat.NowRank,
HisRank: ls.stat.HisRank,
Like: ls.stat.Like,
}
for cluster, arc := range s.arcRPCs {
if err = arc.SetStat2(c, st); err != nil {
log.Error("s.arcRPC.SetStat2(%s) (%+v) error(%v)", cluster, st, err)
}
}
}
}