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,21 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/job/main/relation-cache/cmd:all-srcs",
"//app/job/main/relation-cache/conf:all-srcs",
"//app/job/main/relation-cache/dao:all-srcs",
"//app/job/main/relation-cache/model:all-srcs",
"//app/job/main/relation-cache/server/http:all-srcs",
"//app/job/main/relation-cache/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,2 @@
# v1.0.0
1. 用于删除所有关系链的缓存信息

View File

@ -0,0 +1,14 @@
# Owner
zhoujiahui
wanghuan01
zhaogangtao
# Author
zhoujiahui
wanghuan01
zhaogangtao
# Reviewer
zhoujiahui
wanghuan01
zhaogangtao

View File

@ -0,0 +1,16 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wanghuan01
- zhaogangtao
- zhoujiahui
labels:
- job
- job/main/relation-cache
- main
options:
no_parent_owners: true
reviewers:
- wanghuan01
- zhaogangtao
- zhoujiahui

View File

@ -0,0 +1,12 @@
# relation-cache-job
# 项目简介
1. 用于关系链的缓存处理任务
# 编译环境
# 依赖包
# 编译执行

View File

@ -0,0 +1 @@
# HTTP API文档

View File

@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["test.toml"],
importpath = "go-common/app/job/main/relation-cache/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/relation-cache/conf:go_default_library",
"//app/job/main/relation-cache/server/http:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace: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,42 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/job/main/relation-cache/conf"
"go-common/app/job/main/relation-cache/server/http"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@ -0,0 +1,35 @@
[mysql]
addr = "127.0.0.1:3306"
dsn = "test:test@tcp(127.0.0.1:3306)/test?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["test:test@tcp(127.0.0.2:3306)/test? timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4","test:test@tcp(127.0.0.3:3306)/test?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[redis]
name = "relation-cache-job"
proto = "tcp"
addr = ""
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[memcache]
name = "relation-cache-job"
proto = "tcp"
addr = ""
active = 50
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"

View File

@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/job/main/relation-cache/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml: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,105 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/trace"
"go-common/library/queue/databus"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Tracer *trace.Config
Redis *redis.Config
Memcache *memcache.Config
MySQL *sql.Config
Ecode *ecode.Config
RelationBinLog *databus.Config
HTTPClient *bm.ClientConfig
CacheTTL *CacheTTL
}
// ClearPath clear cache path
// type ClearPath struct {
// Following string
// Follower string
// Stat string
// }
// CacheTTL is
type CacheTTL struct {
RelationTTL xtime.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@ -0,0 +1,59 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"relation.go",
],
importpath = "go-common/app/job/main/relation-cache/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/relation-cache/conf:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/time: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 = [
"dao_test.go",
"relation_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/relation-cache/conf:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@ -0,0 +1,59 @@
package dao
import (
"context"
"time"
"go-common/app/job/main/relation-cache/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
)
// Dao dao
type Dao struct {
*cacheTTL
c *conf.Config
mc *memcache.Pool
redis *redis.Pool
db *xsql.DB
client *bm.Client
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
cacheTTL: &cacheTTL{
RelationTTL: asSecond(c.CacheTTL.RelationTTL),
},
c: c,
mc: memcache.NewPool(c.Memcache),
redis: redis.NewPool(c.Redis),
db: xsql.NewMySQL(c.MySQL),
client: bm.NewClient(c.HTTPClient),
}
return
}
type cacheTTL struct {
RelationTTL int64
}
func asSecond(d xtime.Duration) int64 {
return int64(time.Duration(d) / time.Second)
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
// TODO: if you need use mc,redis, please add
return d.db.Ping(c)
}

View File

@ -0,0 +1,33 @@
package dao
import (
"flag"
"go-common/app/job/main/relation-cache/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.relation-cache-job")
flag.Set("conf_token", "db8cc8578e4447edfe1e7385c62be0e5")
flag.Set("tree_id", "56981")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@ -0,0 +1,164 @@
package dao
import (
"context"
"fmt"
"strconv"
relation "go-common/app/service/main/relation/model"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/log"
xtime "go-common/library/time"
)
const (
_prefixFollowings = "at_"
_prefixTags = "tags_" // user tag info.
_prefixFollowing = "pb_a_"
_prefixStat = "c_" // key of stat
_prefixTagCount = "rs_tmtc_%d" // key of relation tag by mid & tag's count
)
func statKey(mid int64) string {
return _prefixStat + strconv.FormatInt(mid, 10)
}
func tagsKey(mid int64) string {
return _prefixTags + strconv.FormatInt(mid, 10)
}
func followingsKey(mid int64) string {
return _prefixFollowings + strconv.FormatInt(mid, 10)
}
func followingKey(mid int64) string {
return _prefixFollowing + strconv.FormatInt(mid, 10)
}
func tagCountKey(mid int64) string {
return fmt.Sprintf(_prefixTagCount, mid)
}
// DelStatCache is
func (d *Dao) DelStatCache(ctx context.Context, mid int64) error {
conn := d.mc.Get(ctx)
defer conn.Close()
if err := conn.Delete(statKey(mid)); err != nil {
if err == memcache.ErrNotFound {
return nil
}
log.Error("Failed to delete stat cache: mid: %d: %+v", mid, err)
return err
}
return nil
}
// DelFollowerCache del follower cache
func (d *Dao) DelFollowerCache(ctx context.Context, fid int64) error {
key := followingKey(fid)
conn := d.mc.Get(ctx)
defer conn.Close()
if err := conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Delete(%s) error(%v)", key, err)
return err
}
}
return nil
}
// DelFollowing del following cache.
func (d *Dao) DelFollowing(c context.Context, mid int64, following *relation.Following) (err error) {
var (
ok bool
key = followingsKey(mid)
)
conn := d.redis.Get(c)
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.RelationTTL)); err != nil {
log.Error("redis.Bool(conn.Do(EXPIRE, %s)) error(%v)", key, err)
} else if ok {
if _, err = conn.Do("HDEL", key, following.Mid); err != nil {
log.Error("conn.Do(HDEL, %s, %d) error(%v)", key, following.Mid, err)
}
}
conn.Close()
return
}
// DelTagsCache is
func (d *Dao) DelTagsCache(ctx context.Context, mid int64) (err error) {
conn := d.mc.Get(ctx)
if err = conn.Delete(tagsKey(mid)); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Delete(%s) error(%v)", tagCountKey(mid), err)
}
}
conn.Close()
return
}
// AddFollowingCache is
func (d *Dao) AddFollowingCache(c context.Context, mid int64, following *relation.Following) (err error) {
var (
ok bool
key = followingsKey(mid)
)
conn := d.redis.Get(c)
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.RelationTTL)); err != nil {
log.Error("redis.Bool(conn.Do(EXPIRE, %s)) error(%v)", key, err)
} else if ok {
var ef []byte
if ef, err = d.encode(following.Attribute, following.MTime, following.Tag, following.Special); err != nil {
return
}
if _, err = conn.Do("HSET", key, following.Mid, ef); err != nil {
log.Error("conn.Do(HSET, %s, %d) error(%v)", key, following.Mid, err)
}
}
conn.Close()
return
}
// encode
func (d *Dao) encode(attribute uint32, mtime xtime.Time, tagids []int64, special int32) (res []byte, err error) {
ft := &relation.FollowingTags{Attr: attribute, Ts: mtime, TagIds: tagids, Special: special}
return ft.Marshal()
}
// DelFollowingCache delete following cache.
func (d *Dao) DelFollowingCache(c context.Context, mid int64) (err error) {
return d.delFollowingCache(c, followingKey(mid))
}
// delFollowingCache delete following cache.
func (d *Dao) delFollowingCache(c context.Context, key string) (err error) {
conn := d.mc.Get(c)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Delete(%s) error(%v)", key, err)
}
}
conn.Close()
return
}
// DelTagCountCache del tag count cache.
func (d *Dao) DelTagCountCache(c context.Context, mid int64) (err error) {
conn := d.mc.Get(c)
if err = conn.Delete(tagCountKey(mid)); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Delete(%s) error(%v)", tagCountKey(mid), err)
}
}
conn.Close()
return
}

View File

@ -0,0 +1,192 @@
package dao
import (
"context"
relation "go-common/app/service/main/relation/model"
xtime "go-common/library/time"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaostatKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("statKey", t, func(ctx convey.C) {
p1 := statKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaotagsKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("tagsKey", t, func(ctx convey.C) {
p1 := tagsKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaofollowingsKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("followingsKey", t, func(ctx convey.C) {
p1 := followingsKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaofollowingKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("followingKey", t, func(ctx convey.C) {
p1 := followingKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaotagCountKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("tagCountKey", t, func(ctx convey.C) {
p1 := tagCountKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoDelStatCache(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
)
convey.Convey("DelStatCache", t, func(ctx convey.C) {
err := d.DelStatCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelFollowerCache(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
)
convey.Convey("DelFollowerCache", t, func(ctx convey.C) {
err := d.DelFollowerCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelFollowing(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
following = &relation.Following{}
)
convey.Convey("DelFollowing", t, func(ctx convey.C) {
err := d.DelFollowing(c, mid, following)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelTagsCache(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
)
convey.Convey("DelTagsCache", t, func(ctx convey.C) {
err := d.DelTagsCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoAddFollowingCache(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
following = &relation.Following{}
)
convey.Convey("AddFollowingCache", t, func(ctx convey.C) {
err := d.AddFollowingCache(c, mid, following)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoencode(t *testing.T) {
var (
attribute = uint32(1)
mtime xtime.Time
tagids = []int64{1}
special = int32(1)
)
convey.Convey("encode", t, func(ctx convey.C) {
res, err := d.encode(attribute, mtime, tagids, special)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoDelFollowingCache(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
)
convey.Convey("DelFollowingCache", t, func(ctx convey.C) {
err := d.DelFollowingCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaodelFollowingCache(t *testing.T) {
var (
c = context.Background()
key = ""
)
convey.Convey("delFollowingCache", t, func(ctx convey.C) {
err := d.delFollowingCache(c, key)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoDelTagCountCache(t *testing.T) {
var (
c = context.Background()
mid = int64(0)
)
convey.Convey("DelTagCountCache", t, func(ctx convey.C) {
err := d.DelTagCountCache(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@ -0,0 +1,31 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"model.go",
"retry.go",
],
importpath = "go-common/app/job/main/relation-cache/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
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,32 @@
package model
import (
"encoding/json"
)
// Message define binlog databus message.
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// Stat is
type Stat struct {
Mid int64 `json:"mid,omitempty"`
Following int64 `json:"following"`
Whisper int64 `json:"whisper"`
Black int64 `json:"black"`
Follower int64 `json:"follower"`
}
// Relation is
type Relation struct {
Mid int64 `json:"mid,omitempty"`
Fid int64 `json:"fid,omitempty"`
Attribute uint32 `json:"attribute"`
Status int `json:"status"`
MTime string `json:"mtime"`
CTime string `json:"ctime"`
}

View File

@ -0,0 +1,26 @@
package model
import (
"time"
)
// Retry is
func Retry(attempts int, sleep time.Duration, fn func() error) error {
if err := fn(); err != nil {
if s, ok := err.(stop); ok {
// Return the original error for later checking
return s.error
}
if attempts--; attempts > 0 {
time.Sleep(sleep)
return Retry(attempts, 2*sleep, fn)
}
return err
}
return nil
}
type stop struct {
error
}

View File

@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/job/main/relation-cache/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/relation-cache/conf:go_default_library",
"//app/job/main/relation-cache/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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,53 @@
package http
import (
"net/http"
"go-common/app/job/main/relation-cache/conf"
"go-common/app/job/main/relation-cache/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
srv *service.Service
vfy *verify.Verify
)
// Init init
func Init(c *conf.Config) {
srv = service.New(c)
vfy = verify.New(c.Verify)
engine := bm.DefaultServer(c.BM)
router(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start() error(%v)", err)
panic(err)
}
}
func router(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/relation-cache")
{
g.GET("/start", vfy.Verify, howToStart)
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// example for http request handler
func howToStart(c *bm.Context) {
c.String(0, "Golang 大法好 !!!")
}

View File

@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"relation.go",
"service.go",
],
importpath = "go-common/app/job/main/relation-cache/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/relation-cache/conf:go_default_library",
"//app/job/main/relation-cache/dao:go_default_library",
"//app/job/main/relation-cache/model:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time: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,149 @@
package service
import (
"context"
"encoding/json"
"strings"
"time"
"go-common/app/job/main/relation-cache/model"
relation "go-common/app/service/main/relation/model"
"go-common/library/log"
"go-common/library/queue/databus"
xtime "go-common/library/time"
"github.com/pkg/errors"
)
const (
_relationFidTable = "user_relation_fid_"
_relationMidTable = "user_relation_mid_"
_relationStatTable = "user_relation_stat_"
_relationTagUserTable = "user_relation_tag_user_"
)
func (s *Service) relationBinLogproc(ctx context.Context) {
for msg := range s.relationBinLog.Messages() {
if err := s.handleRelationBinLog(ctx, msg); err != nil {
log.Error("Failed to handle relation binlog: %s: %+v", BeautifyMessage(msg), err)
continue
}
log.Info("Succeed to handle relation binlog: %s", BeautifyMessage(msg))
}
}
func (s *Service) handleRelationBinLog(ctx context.Context, msg *databus.Message) error {
defer func() {
if err := msg.Commit(); err != nil {
log.Error("Failed to commit message: %+v", BeautifyMessage(msg))
return
}
}()
mu := &model.Message{}
if err := json.Unmarshal(msg.Value, mu); err != nil {
return errors.WithStack(err)
}
switch {
case strings.HasPrefix(mu.Table, _relationStatTable):
if err := s.stat(ctx, mu.Action, mu.New, mu.Old); err != nil {
return err
}
case strings.HasPrefix(mu.Table, _relationMidTable):
if err := s.relationMid(ctx, mu.Action, mu.New, mu.Old); err != nil {
return err
}
case strings.HasPrefix(mu.Table, _relationFidTable):
if err := s.relationFid(ctx, mu.Action, mu.New, mu.Old); err != nil {
return err
}
case strings.HasPrefix(mu.Table, _relationTagUserTable):
if err := s.tagUser(ctx, mu.New); err != nil {
return err
}
}
return nil
}
// stat
func (s *Service) stat(ctx context.Context, action string, nwMsg []byte, oldMsg []byte) (err error) {
ms := &model.Stat{}
if err = json.Unmarshal(nwMsg, ms); err != nil {
log.Error("json.Unmarshal(%v) error(%v)", nwMsg, err)
return
}
mo := &model.Stat{}
if len(oldMsg) > 0 {
if err = json.Unmarshal(oldMsg, mo); err != nil {
log.Error("json.Unmarshal(%v) error(%v)", oldMsg, err)
err = nil
}
}
return s.dao.DelStatCache(ctx, ms.Mid)
}
// relationMid
func (s *Service) relationMid(ctx context.Context, action string, nwMsg []byte, oldMsg []byte) error {
mr := &model.Relation{}
if err := json.Unmarshal(nwMsg, mr); err != nil {
return errors.WithStack(err)
}
f := &relation.Following{
Mid: mr.Fid,
Attribute: mr.Attribute,
MTime: xtime.Time(time.Now().Unix()),
}
if err := s.upFollowingCache(ctx, mr.Mid, f); err != nil {
return err
}
return s.dao.DelTagsCache(ctx, mr.Mid)
}
// relationFid
func (s *Service) relationFid(ctx context.Context, action string, nwMsg []byte, oldMsg []byte) error {
var or *model.Relation
mr := &model.Relation{}
if err := json.Unmarshal(nwMsg, mr); err != nil {
log.Error("json.Unmarshal(%v) error(%v)", nwMsg, err)
return err
}
if len(oldMsg) > 0 {
or = new(model.Relation)
if err := json.Unmarshal(oldMsg, or); err != nil {
log.Error("json.Unmarshal(%v) error(%v)", oldMsg, err)
}
}
return s.dao.DelFollowerCache(ctx, mr.Fid)
}
func (s *Service) tagUser(ctx context.Context, newMsg []byte) (err error) {
var tags struct {
Fid int64 `json:"fid"`
Mid int64 `json:"mid"`
}
if err = json.Unmarshal(newMsg, &tags); err != nil {
log.Error("json.Unmarshal err(%v)", err)
return
}
return s.dao.DelTagsCache(ctx, tags.Mid)
}
func (s *Service) upFollowingCache(c context.Context, mid int64, f *relation.Following) (err error) {
if f.Attribute == 0 {
s.dao.DelFollowing(c, mid, f)
} else {
if err = s.dao.AddFollowingCache(c, mid, f); err != nil {
return
}
}
if err = s.dao.DelFollowingCache(c, mid); err != nil {
return
}
return s.dao.DelTagCountCache(c, mid)
}

View File

@ -0,0 +1,68 @@
package service
import (
"context"
"fmt"
"sync"
"go-common/app/job/main/relation-cache/conf"
"go-common/app/job/main/relation-cache/dao"
"go-common/library/queue/databus"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
relationBinLog *databus.Databus
waiter *sync.WaitGroup
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
relationBinLog: databus.New(c.RelationBinLog),
waiter: &sync.WaitGroup{},
}
s.Start(context.Background())
return s
}
// Start to handle requests
func (s *Service) Start(ctx context.Context) {
for i := 0; i < 50; i++ {
go s.relationBinLogproc(context.Background())
}
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}
// BeautifyMessage is
func BeautifyMessage(msg *databus.Message) string {
pmsg := struct {
Key string `json:"key"`
Value string `json:"value"`
Topic string `json:"topic"`
Partition int32 `json:"partition"`
Offset int64 `json:"offset"`
Timestamp int64 `json:"timestamp"`
}{
Key: msg.Key,
Value: string(msg.Value),
Topic: msg.Topic,
Partition: msg.Partition,
Offset: msg.Offset,
Timestamp: msg.Timestamp,
}
return fmt.Sprintf("%+v", pmsg)
}