Create & Init Project...
This commit is contained in:
21
app/job/main/figure-timer/BUILD
Normal file
21
app/job/main/figure-timer/BUILD
Normal 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/figure-timer/cmd:all-srcs",
|
||||
"//app/job/main/figure-timer/conf:all-srcs",
|
||||
"//app/job/main/figure-timer/dao:all-srcs",
|
||||
"//app/job/main/figure-timer/http:all-srcs",
|
||||
"//app/job/main/figure-timer/model:all-srcs",
|
||||
"//app/job/main/figure-timer/service:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
70
app/job/main/figure-timer/CHANGELOG.md
Normal file
70
app/job/main/figure-timer/CHANGELOG.md
Normal file
@ -0,0 +1,70 @@
|
||||
# v1.4.1
|
||||
1. 优化ping , 去掉中间件ping
|
||||
|
||||
# v1.4.0
|
||||
> 1.change hbase sdk
|
||||
|
||||
# v1.3.0
|
||||
> 1.rebuild
|
||||
|
||||
# v1.2.0
|
||||
> 1.http router to bm
|
||||
|
||||
# v1.1.6
|
||||
> 1.update path
|
||||
|
||||
# v1.1.5
|
||||
> 1.remove stastd
|
||||
|
||||
# v1.1.4
|
||||
> 1.全量计算信用分
|
||||
|
||||
# v1.1.3
|
||||
> 1.放慢figure user upset速度
|
||||
|
||||
# v1.1.2
|
||||
> 1.修复重新计算record的能力
|
||||
|
||||
# v1.1.1
|
||||
> 1.修复record值错误
|
||||
> 2.增加重新计算record的能力
|
||||
> 3.Dao interface for mock
|
||||
|
||||
# v1.1.0
|
||||
> 1.计算框架支持支付,弹幕举报,评论举报
|
||||
|
||||
# v1.0.10
|
||||
> 1.fix redis expire
|
||||
|
||||
# v1.0.9
|
||||
> 1.hbase api兼容性修改
|
||||
|
||||
# v1.0.8
|
||||
> 1.增加prom监控
|
||||
|
||||
# v1.0.7
|
||||
> 1.增加自动计算分值段并落库
|
||||
|
||||
# v1.0.6
|
||||
> 1.添加开始mid区间配置
|
||||
|
||||
# v1.0.5
|
||||
> 1.vip类型变更
|
||||
|
||||
# v1.0.4
|
||||
> 1.调整参数
|
||||
> 2.修改spy分值初始化方式
|
||||
|
||||
# v1.0.3
|
||||
> 1.修复hbase列类型
|
||||
|
||||
# v1.0.2
|
||||
> 1.ActionCounters获取换成Get获取
|
||||
|
||||
# v1.0.1
|
||||
> 1.增加log
|
||||
> 2.修复hbase解码问题
|
||||
|
||||
# v1.0.0
|
||||
> 1.版本初始化
|
||||
|
9
app/job/main/figure-timer/CONTRIBUTORS.md
Normal file
9
app/job/main/figure-timer/CONTRIBUTORS.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Owner
|
||||
zhaogangtao
|
||||
|
||||
# Author
|
||||
muyang
|
||||
|
||||
# Reviewer
|
||||
zhaogangtao
|
||||
linmiao
|
15
app/job/main/figure-timer/OWNERS
Normal file
15
app/job/main/figure-timer/OWNERS
Normal file
@ -0,0 +1,15 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- muyang
|
||||
- zhaogangtao
|
||||
labels:
|
||||
- job
|
||||
- job/main/figure-timer
|
||||
- main
|
||||
options:
|
||||
no_parent_owners: true
|
||||
reviewers:
|
||||
- linmiao
|
||||
- muyang
|
||||
- zhaogangtao
|
10
app/job/main/figure-timer/README.md
Normal file
10
app/job/main/figure-timer/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
#### figure-timer
|
||||
|
||||
##### 项目简介
|
||||
> 1.异步任务,周期结算用户信用分值
|
||||
|
||||
##### 编译环境
|
||||
> 请只用golang v1.8.x以上版本编译执行。
|
||||
|
||||
##### 依赖包
|
||||
> 1.公共包go-common
|
43
app/job/main/figure-timer/cmd/BUILD
Normal file
43
app/job/main/figure-timer/cmd/BUILD
Normal 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 = ["figure-timer-job-test.toml"],
|
||||
importpath = "go-common/app/job/main/figure-timer/cmd",
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//app/job/main/figure-timer/conf:go_default_library",
|
||||
"//app/job/main/figure-timer/http:go_default_library",
|
||||
"//app/job/main/figure-timer/service:go_default_library",
|
||||
"//library/log:go_default_library",
|
||||
"//library/syscall: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"],
|
||||
)
|
143
app/job/main/figure-timer/cmd/figure-timer-job-test.toml
Normal file
143
app/job/main/figure-timer/cmd/figure-timer-job-test.toml
Normal file
@ -0,0 +1,143 @@
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
version = "1.0.0"
|
||||
user = "nobody"
|
||||
pid = "/tmp/figure-timer-job.pid"
|
||||
dir = "./"
|
||||
perf = "0.0.0.0:7080"
|
||||
family = "figure-timer-job"
|
||||
address = "172.16.0.148"
|
||||
|
||||
[log]
|
||||
dir = "/data/log/figure-timer-job/"
|
||||
|
||||
[bm]
|
||||
addr = "0.0.0.0:7082"
|
||||
timeout = "1s"
|
||||
maxListen = 100
|
||||
|
||||
[tracer]
|
||||
proto = "udp"
|
||||
addr = "172.16.33.46:5140"
|
||||
tag = "platform/figure-timer-job"
|
||||
|
||||
[mysql]
|
||||
addr = "172.16.33.205:3308"
|
||||
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_figure?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
|
||||
active = 5
|
||||
idle = 2
|
||||
queryTimeout = "1s"
|
||||
execTimeout = "1s"
|
||||
tranTimeout = "1s"
|
||||
[mysql.breaker]
|
||||
window = "3s"
|
||||
sleep = "100ms"
|
||||
bucket = 10
|
||||
ratio = 0.5
|
||||
request = 100
|
||||
|
||||
[hbase]
|
||||
master = ""
|
||||
meta = ""
|
||||
dialTimeout = "1s"
|
||||
readTimeout = "1s"
|
||||
readsTimeout = "1s"
|
||||
writeTimeout = "1s"
|
||||
writesTimeout = "1s"
|
||||
[hbase.zookeeper]
|
||||
root = ""
|
||||
addrs = ["10.23.66.16:2181"]
|
||||
timeout = "30s"
|
||||
|
||||
[redis]
|
||||
name = "figure-timer-job"
|
||||
proto = "tcp"
|
||||
addr = "172.16.33.54:6379"
|
||||
idle = 100
|
||||
active = 100
|
||||
dialTimeout = "1s"
|
||||
readTimeout = "1s"
|
||||
writeTimeout = "1s"
|
||||
idleTimeout = "10s"
|
||||
expire = "192h"
|
||||
|
||||
[property]
|
||||
PendingMidStart = 0
|
||||
PendingMidShard = 10000
|
||||
PendingMidRetry = 3
|
||||
CalcWeekOffset = 1
|
||||
CycleCron = "0 0 0 * * 1"
|
||||
ConcurrencySize = 16
|
||||
FixRecord = true
|
||||
CycleAll = true
|
||||
CycleAllCron = "0 0 0 * * 1"
|
||||
[property.calc]
|
||||
K1 = 0.1
|
||||
K2 = 0.1
|
||||
K3 = 0.1
|
||||
K4 = 0.1
|
||||
K5 = 0.1
|
||||
InitLawfulScore = 10000
|
||||
InitWideScore = 0
|
||||
InitFriendlyScore = 5000
|
||||
InitBountyScore = 0
|
||||
InitCreativityScore = 0
|
||||
lawfulNegMax = 10000.0
|
||||
lawfulPosMax = 10000.0
|
||||
lawfulPosK = 0.002
|
||||
lawfulNegK1 = 0.03
|
||||
lawfulNegK2 = 0.02
|
||||
lawfulPosL = 200.0
|
||||
lawfulNegL = 200.0
|
||||
lawfulPosC1 = 1.0
|
||||
lawfulPosC2 = 1.0
|
||||
lawfulPosC3 = 1.0
|
||||
lawfulNegC1 = 1.0
|
||||
lawfulNegC2 = 5.0
|
||||
lawfulNegC3 = 5.0
|
||||
lawfulPosQ1 = 1.0
|
||||
lawfulPosQ2 = 1.0
|
||||
lawfulPosQ3 = 1.0
|
||||
lawfulNegQ1 = 1.0
|
||||
lawfulNegQ2 = 1.0
|
||||
lawfulNegQ3 = 1.0
|
||||
widePosMax = 15000.0
|
||||
widePosK = 0.004
|
||||
wideC1 = 2.0
|
||||
wideQ1 = 1.0
|
||||
wideC2 = 0.01
|
||||
wideQ2 = 1.0
|
||||
friendlyPosMax = 15000.0
|
||||
friendlyNegMax = 20000.0
|
||||
friendlyPosK = 0.004
|
||||
friendlyNegK = 0.004
|
||||
friendlyPosL = 200.0
|
||||
friendlyNegL = 200.0
|
||||
friendlyPosQ1 = 1.0
|
||||
friendlyPosC1 = 1.0
|
||||
friendlyPosQ2 = 1.0
|
||||
friendlyPosC2 = 2.0
|
||||
friendlyPosQ3 = 1.0
|
||||
friendlyPosC3 = 1.0
|
||||
friendlyNegQ1 = 1.0
|
||||
friendlyNegC1 = 150.0
|
||||
friendlyNegQ2 = 1.0
|
||||
friendlyNegC2 = 80.0
|
||||
friendlyNegQ3 = 1.0
|
||||
friendlyNegC3 = 10.0
|
||||
friendlyNegQ4 = 1.0
|
||||
friendlyNegC4 = 5.0
|
||||
bountyMax = 15000.0
|
||||
bountyPosL = 200.0
|
||||
bountyK = 0.000015
|
||||
bountyQ1 = 1.0
|
||||
bountyC1 = 15.0
|
||||
bountyQ2 = 2.5
|
||||
bountyC2 = 1.0
|
||||
bountyQ3 = 1.0
|
||||
bountyC3 = 1.0
|
||||
creativityPosMax = 7000.0
|
||||
creativityPosK = 0.004
|
||||
creativityPosL1 = 200.0
|
||||
creativityQ1 = 1.0
|
||||
creativityC1 = 0.1
|
52
app/job/main/figure-timer/cmd/main.go
Normal file
52
app/job/main/figure-timer/cmd/main.go
Normal file
@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/http"
|
||||
"go-common/app/job/main/figure-timer/service"
|
||||
"go-common/library/log"
|
||||
"go-common/library/syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
srv *service.Service
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if err := conf.Init(); err != nil {
|
||||
log.Error("conf.Init() error(%v)", err)
|
||||
panic(err)
|
||||
}
|
||||
log.Init(conf.Conf.Log)
|
||||
defer log.Close()
|
||||
srv = service.New(conf.Conf)
|
||||
http.Init(srv)
|
||||
log.Info("figure-timer-job start")
|
||||
signalHandler()
|
||||
}
|
||||
|
||||
func signalHandler() {
|
||||
var (
|
||||
ch = make(chan os.Signal, 1)
|
||||
)
|
||||
signal.Notify(ch, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT, syscall.SIGSTOP)
|
||||
for {
|
||||
si := <-ch
|
||||
log.Info("figure-timer-job got a signal (%d)", si)
|
||||
switch si {
|
||||
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
|
||||
srv.Close()
|
||||
srv.Wait()
|
||||
log.Info("figure-timer-job exit")
|
||||
return
|
||||
case syscall.SIGHUP:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
78
app/job/main/figure-timer/conf.toml
Normal file
78
app/job/main/figure-timer/conf.toml
Normal file
@ -0,0 +1,78 @@
|
||||
[property]
|
||||
# 结算开始分片index(方便debug)
|
||||
PendingMidStart = 0
|
||||
# redis中用户列表分片数
|
||||
PendingMidShard = 10000
|
||||
# 从redis取出用户列表的重试次数(防止一次失败,导致本次结算不完整)
|
||||
PendingMidRetry = 3
|
||||
# 计算周偏移,0:结算本周分值,1:计算上周分值...以此类推
|
||||
CalcWeekOffset = 1
|
||||
# 周期计算信用分的cron表达式
|
||||
CycleCron = "0 0 0 * * 1"
|
||||
# 计算分值并发数
|
||||
ConcurrencySize = 16
|
||||
[property.calc]
|
||||
K1 = 0.1
|
||||
K2 = 0.1
|
||||
K3 = 0.1
|
||||
K4 = 0.1
|
||||
K5 = 0.1
|
||||
InitLawfulScore = 10000
|
||||
InitWideScore = 0
|
||||
InitFriendlyScore = 5000
|
||||
InitBountyScore = 0
|
||||
InitCreativityScore = 0
|
||||
lawfulNegMax = 10000.0
|
||||
lawfulPosMax = 10000.0
|
||||
lawfulPosK = 0.002
|
||||
lawfulNegK1 = 0.03
|
||||
lawfulNegK2 = 0.02
|
||||
lawfulPosL = 200.0
|
||||
lawfulNegL = 200.0
|
||||
lawfulPosC1 = 1.0
|
||||
lawfulPosC2 = 1.0
|
||||
lawfulPosC3 = 1.0
|
||||
lawfulNegC1 = 1.0
|
||||
lawfulNegC2 = 5.0
|
||||
lawfulNegC3 = 5.0
|
||||
lawfulPosQ1 = 1.0
|
||||
lawfulPosQ2 = 1.0
|
||||
lawfulPosQ3 = 1.0
|
||||
lawfulNegQ1 = 1.0
|
||||
lawfulNegQ2 = 1.0
|
||||
lawfulNegQ3 = 1.0
|
||||
widePosMax = 15000.0
|
||||
widePosK = 0.004
|
||||
wideC1 = 2.0
|
||||
wideQ1 = 1.0
|
||||
wideC2 = 0.01
|
||||
wideQ2 = 1.0
|
||||
friendlyPosMax = 15000.0
|
||||
friendlyNegMax = 20000.0
|
||||
friendlyPosK = 0.004
|
||||
friendlyNegK = 0.004
|
||||
friendlyPosL = 200.0
|
||||
friendlyNegL = 200.0
|
||||
friendlyPosQ1 = 1.0
|
||||
friendlyPosC1 = 1.0
|
||||
friendlyPosQ2 = 1.0
|
||||
friendlyPosC2 = 2.0
|
||||
friendlyPosQ3 = 1.0
|
||||
friendlyPosC3 = 1.0
|
||||
friendlyNegQ1 = 1.0
|
||||
friendlyNegC1 = 150.0
|
||||
friendlyNegQ2 = 1.0
|
||||
friendlyNegC2 = 80.0
|
||||
friendlyNegQ3 = 1.0
|
||||
friendlyNegC3 = 10.0
|
||||
friendlyNegQ4 = 1.0
|
||||
friendlyNegC4 = 5.0
|
||||
bountyMax = 15000.0
|
||||
bountyK = 0.005
|
||||
bountyQ1 = 1.0
|
||||
bountyC1 = 15.0
|
||||
creativityPosMax = 7000.0
|
||||
creativityPosK = 0.004
|
||||
creativityPosL1 = 200.0
|
||||
creativityQ1 = 1.0
|
||||
creativityC1 = 0.1
|
48
app/job/main/figure-timer/conf/BUILD
Normal file
48
app/job/main/figure-timer/conf/BUILD
Normal file
@ -0,0 +1,48 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_test",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["conf_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
rundir = ".",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["conf.go"],
|
||||
importpath = "go-common/app/job/main/figure-timer/conf",
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//library/cache/redis:go_default_library",
|
||||
"//library/conf:go_default_library",
|
||||
"//library/database/hbase.v2: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",
|
||||
"//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"],
|
||||
)
|
191
app/job/main/figure-timer/conf/conf.go
Normal file
191
app/job/main/figure-timer/conf/conf.go
Normal file
@ -0,0 +1,191 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
|
||||
"go-common/library/cache/redis"
|
||||
"go-common/library/conf"
|
||||
"go-common/library/database/hbase.v2"
|
||||
"go-common/library/database/sql"
|
||||
"go-common/library/log"
|
||||
bm "go-common/library/net/http/blademaster"
|
||||
xtime "go-common/library/time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
// Conf global variable.
|
||||
var (
|
||||
Conf = &Config{}
|
||||
client *conf.Client
|
||||
confPath string
|
||||
)
|
||||
|
||||
// Config struct of conf.
|
||||
type Config struct {
|
||||
// base
|
||||
// log
|
||||
Log *log.Config
|
||||
// mysql
|
||||
Mysql *sql.Config
|
||||
// http
|
||||
BM *bm.ServerConfig
|
||||
// hbase
|
||||
Hbase *HBaseConfig
|
||||
// redis
|
||||
Redis *Redis
|
||||
// extra property
|
||||
Property *Property
|
||||
}
|
||||
|
||||
// HBaseConfig is.
|
||||
type HBaseConfig struct {
|
||||
*hbase.Config
|
||||
ReadTimeout xtime.Duration
|
||||
WriteTimeout xtime.Duration
|
||||
}
|
||||
|
||||
// Redis redis.
|
||||
type Redis struct {
|
||||
*redis.Config
|
||||
Expire xtime.Duration
|
||||
}
|
||||
|
||||
// Property figure conf
|
||||
type Property struct {
|
||||
PendingMidStart int64
|
||||
PendingMidShard int64
|
||||
PendingMidRetry int64
|
||||
CalcWeekOffset int64
|
||||
CycleCron string
|
||||
ConcurrencySize int64
|
||||
FixRecord bool
|
||||
CycleAll bool
|
||||
CycleAllCron string
|
||||
Calc *Calc
|
||||
}
|
||||
|
||||
// Calc figure calc config
|
||||
type Calc struct {
|
||||
InitLawfulScore int64
|
||||
InitWideScore int64
|
||||
InitFriendlyScore int64
|
||||
InitBountyScore int64
|
||||
InitCreativityScore int64
|
||||
K1 float64
|
||||
K2 float64
|
||||
K3 float64
|
||||
K4 float64
|
||||
K5 float64
|
||||
LawfulNegMax float64
|
||||
LawfulPosMax float64
|
||||
LawfulPosK float64
|
||||
LawfulNegK1 float64
|
||||
LawfulNegK2 float64
|
||||
LawfulPosL float64
|
||||
LawfulNegL float64
|
||||
LawfulPosC1 float64
|
||||
LawfulPosC2 float64
|
||||
LawfulPosC3 float64
|
||||
LawfulNegC1 float64
|
||||
LawfulNegC2 float64
|
||||
LawfulNegC3 float64
|
||||
LawfulPosQ1 float64
|
||||
LawfulPosQ2 float64
|
||||
LawfulPosQ3 float64
|
||||
LawfulNegQ1 float64
|
||||
LawfulNegQ2 float64
|
||||
LawfulNegQ3 float64
|
||||
WidePosMax float64
|
||||
WidePosK float64
|
||||
WideC1 float64
|
||||
WideQ1 float64
|
||||
WideC2 float64
|
||||
WideQ2 float64
|
||||
FriendlyPosMax float64
|
||||
FriendlyNegMax float64
|
||||
FriendlyPosK float64
|
||||
FriendlyNegK float64
|
||||
FriendlyPosL float64
|
||||
FriendlyNegL float64
|
||||
FriendlyPosQ1 float64
|
||||
FriendlyPosC1 float64
|
||||
FriendlyPosQ2 float64
|
||||
FriendlyPosC2 float64
|
||||
FriendlyPosQ3 float64
|
||||
FriendlyPosC3 float64
|
||||
FriendlyNegQ1 float64
|
||||
FriendlyNegC1 float64
|
||||
FriendlyNegQ2 float64
|
||||
FriendlyNegC2 float64
|
||||
FriendlyNegQ3 float64
|
||||
FriendlyNegC3 float64
|
||||
FriendlyNegQ4 float64
|
||||
FriendlyNegC4 float64
|
||||
BountyMax float64
|
||||
BountyPosL float64
|
||||
BountyK float64
|
||||
BountyQ1 float64
|
||||
BountyC1 float64
|
||||
BountyQ2 float64
|
||||
BountyC2 float64
|
||||
BountyQ3 float64
|
||||
BountyC3 float64
|
||||
CreativityPosMax float64
|
||||
CreativityPosK float64
|
||||
CreativityPosL1 float64
|
||||
CreativityQ1 float64
|
||||
CreativityC1 float64
|
||||
}
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&confPath, "conf", "", "default config path")
|
||||
}
|
||||
|
||||
// Init create config instance.
|
||||
func Init() (err 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
|
||||
}
|
23
app/job/main/figure-timer/conf/conf_test.go
Normal file
23
app/job/main/figure-timer/conf/conf_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Set("conf", "../cmd/figure-timer-job-test.toml")
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
Convey("TEST conf", t, func() {
|
||||
err := Init()
|
||||
So(err, ShouldBeNil)
|
||||
So(Conf.Property, ShouldNotBeNil)
|
||||
So(Conf.Property.Calc, ShouldNotBeNil)
|
||||
fmt.Printf("%+v", Conf.Property.Calc)
|
||||
})
|
||||
}
|
61
app/job/main/figure-timer/dao/BUILD
Normal file
61
app/job/main/figure-timer/dao/BUILD
Normal 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 = ["dao_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
rundir = ".",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//app/job/main/figure-timer/conf:go_default_library",
|
||||
"//app/job/main/figure-timer/model:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"dao.go",
|
||||
"hbase.go",
|
||||
"mysql.go",
|
||||
"redis.go",
|
||||
],
|
||||
importpath = "go-common/app/job/main/figure-timer/dao",
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//app/job/main/figure-timer/conf:go_default_library",
|
||||
"//app/job/main/figure-timer/model:go_default_library",
|
||||
"//library/cache/redis:go_default_library",
|
||||
"//library/database/hbase.v2:go_default_library",
|
||||
"//library/database/sql:go_default_library",
|
||||
"//library/log:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/github.com/tsuna/gohbase/hrpc:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//app/job/main/figure-timer/dao/mock_dao:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
94
app/job/main/figure-timer/dao/dao.go
Normal file
94
app/job/main/figure-timer/dao/dao.go
Normal file
@ -0,0 +1,94 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/cache/redis"
|
||||
"go-common/library/database/hbase.v2"
|
||||
"go-common/library/database/sql"
|
||||
)
|
||||
|
||||
// Int is dao interface
|
||||
type Int interface {
|
||||
HBase
|
||||
Mysql
|
||||
Redis
|
||||
Close()
|
||||
Ping(c context.Context) error
|
||||
}
|
||||
|
||||
// HBase dao hbase interface
|
||||
type HBase interface {
|
||||
UserInfo(c context.Context, mid int64, weekVer int64) (userInfo *model.UserInfo, err error)
|
||||
PutCalcRecord(c context.Context, record *model.FigureRecord, weekTS int64) (err error)
|
||||
CalcRecords(c context.Context, mid int64, weekTSFrom, weekTSTo int64) (figureRecords []*model.FigureRecord, err error)
|
||||
ActionCounter(c context.Context, mid int64, ts int64) (counter *model.ActionCounter, err error)
|
||||
}
|
||||
|
||||
// Mysql dao mysql interface
|
||||
type Mysql interface {
|
||||
Figure(c context.Context, mid int64) (figure *model.Figure, err error)
|
||||
Figures(c context.Context, fromMid int64, limit int) (figures []*model.Figure, end bool, err error)
|
||||
UpsertFigure(c context.Context, figure *model.Figure) (id int64, err error)
|
||||
InsertRankHistory(c context.Context, rank *model.Rank) (id int64, err error)
|
||||
UpsertRank(c context.Context, rank *model.Rank) (id int64, err error)
|
||||
}
|
||||
|
||||
// Redis dao redis interface
|
||||
type Redis interface {
|
||||
FigureCache(c context.Context, mid int64) (figure *model.Figure, err error)
|
||||
SetFigureCache(c context.Context, figure *model.Figure) (err error)
|
||||
PendingMidsCache(c context.Context, version int64, shard int64) (mids []int64, err error)
|
||||
RemoveCache(c context.Context, mid int64) (err error)
|
||||
}
|
||||
|
||||
// Dao struct info of Dao.
|
||||
type Dao struct {
|
||||
c *conf.Config
|
||||
mysql *sql.DB
|
||||
hbase *hbase.Client
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
}
|
||||
|
||||
// New new a Dao and return.
|
||||
func New(c *conf.Config) (d *Dao) {
|
||||
d = &Dao{
|
||||
c: c,
|
||||
mysql: sql.NewMySQL(c.Mysql),
|
||||
hbase: hbase.NewClient(c.Hbase.Config),
|
||||
redis: redis.NewPool(c.Redis.Config),
|
||||
redisExpire: int32(time.Duration(c.Redis.Expire) / time.Second),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close close connections of mc, redis, db.
|
||||
func (d *Dao) Close() {
|
||||
if d.mysql != nil {
|
||||
d.mysql.Close()
|
||||
}
|
||||
if d.redis != nil {
|
||||
d.redis.Close()
|
||||
}
|
||||
if d.hbase != nil {
|
||||
d.hbase.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Ping ping health of db.
|
||||
func (d *Dao) Ping(c context.Context) (err error) {
|
||||
if err = d.mysql.Ping(c); err != nil {
|
||||
return
|
||||
}
|
||||
// if err = d.hbase.Ping(c); err != nil {
|
||||
// return
|
||||
// }
|
||||
if err = d.PingRedis(c); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
221
app/job/main/figure-timer/dao/dao_test.go
Normal file
221
app/job/main/figure-timer/dao/dao_test.go
Normal file
@ -0,0 +1,221 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
// "encoding/binary"
|
||||
"flag"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
// "go-common/library/log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
var (
|
||||
dao *Dao
|
||||
ctx = context.TODO()
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
flag.Set("conf", "../cmd/figure-timer-job-test.toml")
|
||||
if err = conf.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dao = New(conf.Conf)
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
Convey("TEST init", t, func() {
|
||||
var err error
|
||||
So(dao.c, ShouldNotBeNil)
|
||||
So(dao.mysql, ShouldNotBeNil)
|
||||
So(dao.hbase, ShouldNotBeNil)
|
||||
So(dao.redis, ShouldNotBeNil)
|
||||
err = dao.Ping(ctx)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMysql(t *testing.T) {
|
||||
Convey("TEST figure", t, func() {
|
||||
var (
|
||||
figure = &model.Figure{
|
||||
Mid: 100,
|
||||
Score: 100,
|
||||
LawfulScore: 50,
|
||||
WideScore: 0,
|
||||
FriendlyScore: 23,
|
||||
BountyScore: 250,
|
||||
CreativityScore: 0,
|
||||
Ver: 0,
|
||||
}
|
||||
figure2 *model.Figure
|
||||
figureRank = &model.Rank{
|
||||
ScoreFrom: 2000,
|
||||
ScoreTo: 3000,
|
||||
Percentage: 50,
|
||||
Ver: 233,
|
||||
}
|
||||
err error
|
||||
)
|
||||
figure.ID, err = dao.UpsertFigure(ctx, figure)
|
||||
So(err, ShouldBeNil)
|
||||
figure2, err = dao.Figure(ctx, figure.Mid)
|
||||
So(err, ShouldBeNil)
|
||||
So(figure2, ShouldNotBeNil)
|
||||
So(figure2.Ctime, ShouldNotBeEmpty)
|
||||
So(figure2.Ctime, ShouldHappenBefore, time.Now().Add(time.Second))
|
||||
So(figure2.Mtime, ShouldNotBeEmpty)
|
||||
So(figure2.Mtime, ShouldHappenBefore, time.Now().Add(time.Second))
|
||||
_, err = dao.InsertRankHistory(ctx, figureRank)
|
||||
So(err, ShouldBeNil)
|
||||
_, err = dao.UpsertRank(ctx, figureRank)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
Convey("TEST figures", t, func() {
|
||||
for shard := 0; shard < 100; shard++ {
|
||||
var (
|
||||
end bool
|
||||
fromMid = int64(shard)
|
||||
figures []*model.Figure
|
||||
err error
|
||||
)
|
||||
for !end {
|
||||
figures, end, err = dao.Figures(ctx, fromMid, 100)
|
||||
So(err, ShouldBeNil)
|
||||
for _, f := range figures {
|
||||
So(f.Mid, ShouldBeGreaterThan, 0)
|
||||
if fromMid < f.Mid {
|
||||
fromMid = f.Mid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestRedis(t *testing.T) {
|
||||
Convey("TEST figure", t, func() {
|
||||
var (
|
||||
figure = &model.Figure{
|
||||
Mid: 23,
|
||||
Score: 100,
|
||||
LawfulScore: 50,
|
||||
WideScore: 0,
|
||||
FriendlyScore: 23,
|
||||
BountyScore: 250,
|
||||
CreativityScore: 0,
|
||||
Ver: 0,
|
||||
}
|
||||
figure2 *model.Figure
|
||||
err error
|
||||
)
|
||||
err = dao.SetFigureCache(ctx, figure)
|
||||
So(err, ShouldBeNil)
|
||||
figure2, err = dao.FigureCache(ctx, figure.Mid)
|
||||
So(err, ShouldBeNil)
|
||||
So(figure2, ShouldNotBeNil)
|
||||
So(figure, ShouldResemble, figure2)
|
||||
})
|
||||
Convey("TEST pending mids", t, func() {
|
||||
var (
|
||||
mid int64 = 23
|
||||
ver int64
|
||||
shard = mid % dao.c.Property.PendingMidShard
|
||||
mids []int64
|
||||
err error
|
||||
)
|
||||
err = dao.setPendingMidCache(ctx, mid, ver)
|
||||
So(err, ShouldBeNil)
|
||||
mids, err = dao.PendingMidsCache(ctx, ver, shard)
|
||||
So(err, ShouldBeNil)
|
||||
So(mids, ShouldNotBeEmpty)
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Dao) setPendingMidCache(c context.Context, mid int64, ver int64) (err error) {
|
||||
var (
|
||||
key = keyPendingMids(ver, mid%d.c.Property.PendingMidShard)
|
||||
conn = d.redis.Get(c)
|
||||
)
|
||||
defer conn.Close()
|
||||
if err = conn.Send("SADD", key, mid); err != nil {
|
||||
err = errors.Wrapf(err, "conn.Send(SADD,%s,%d)", key, mid)
|
||||
return
|
||||
}
|
||||
if err = conn.Send("EXPIRE", key, d); err != nil {
|
||||
err = errors.Wrapf(err, "conn.Send(EXPIRE,%s,%v)", key, d)
|
||||
return
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
if _, err = conn.Receive(); err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func testHbase(t *testing.T) {
|
||||
// Convey("TEST figure_activity", t, func() {
|
||||
// var (
|
||||
// mid int64 = 15555180
|
||||
// err error
|
||||
// weekVer = time.Date(2017, 10, 2, 0, 0, 0, 0, time.Local).Unix()
|
||||
// weekVerFrom = time.Date(2016, 10, 3, 0, 0, 0, 0, time.Local).Unix()
|
||||
// weekVerTo = time.Date(2017, 9, 25, 0, 0, 0, 0, time.Local).Unix()
|
||||
// userInfo *model.UserInfo
|
||||
// figureRecord = &model.FigureRecord{
|
||||
// Mid: mid,
|
||||
// XPosLawful: 12,
|
||||
// XNegLawful: 2,
|
||||
// XPosWide: 12,
|
||||
// XNegWide: 13,
|
||||
// XPosFriendly: 233,
|
||||
// XNegFriendly: 234,
|
||||
// XPosCreativity: 0,
|
||||
// XNegCreativity: 1,
|
||||
// XPosBounty: -250,
|
||||
// XNegBounty: -251,
|
||||
// }
|
||||
// figureRecords []*model.FigureRecord
|
||||
// )
|
||||
// err = dao.putSpyScore(ctx, mid, 100)
|
||||
// So(err, ShouldBeNil)
|
||||
// userInfo, err = dao.UserInfo(ctx, mid, weekVer)
|
||||
// So(err, ShouldBeNil)
|
||||
// So(userInfo, ShouldNotBeNil)
|
||||
|
||||
// err = dao.PutCalcRecord(ctx, figureRecord, time.Date(2016, 12, 3, 0, 0, 0, 0, time.Local).Unix())
|
||||
// So(err, ShouldBeNil)
|
||||
|
||||
// figureRecords, err = dao.CalcRecords(ctx, mid, weekVerFrom, weekVerTo+1)
|
||||
// So(err, ShouldBeNil)
|
||||
// So(figureRecords, ShouldNotBeEmpty)
|
||||
// })
|
||||
// }
|
||||
|
||||
// // PutSpyScore add spy score info.
|
||||
// func (d *Dao) putSpyScore(c context.Context, mid int64, score int8) (err error) {
|
||||
// var (
|
||||
// key = rowKeyUserInfo(mid)
|
||||
// scoreB = make([]byte, 2)
|
||||
// ctx, cancel = context.WithTimeout(c, time.Duration(conf.Conf.Hbase.WriteTimeout))
|
||||
// )
|
||||
// defer cancel()
|
||||
// binary.BigEndian.PutUint16(scoreB, uint16(score))
|
||||
// values := map[string]map[string][]byte{_hbaseUserFC: map[string][]byte{_hbaseUserQSpy: scoreB}}
|
||||
// if _, err = d.hbase.PutStr(ctx, _hbaseUserTable, key, values); err != nil {
|
||||
// log.Error("hbase.PutStr(%s, %s, %v) error(%v)", _hbaseUserTable, key, values, err)
|
||||
// return
|
||||
// }
|
||||
// return
|
||||
// }
|
353
app/job/main/figure-timer/dao/hbase.go
Normal file
353
app/job/main/figure-timer/dao/hbase.go
Normal file
@ -0,0 +1,353 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tsuna/gohbase/hrpc"
|
||||
)
|
||||
|
||||
var (
|
||||
// record
|
||||
_hbaseRecordTable = "ugc:figurecalcrecord"
|
||||
_hbaseRecordFC = "x"
|
||||
_hbaseRecordQLawfulPosX = "pos_lawful"
|
||||
_hbaseRecordQLawfulNegX = "neg_lawful"
|
||||
_hbaseRecordQWidePosX = "pos_wide"
|
||||
_hbaseRecordQWideNegX = "neg_wide"
|
||||
_hbaseRecordQFriendlyPosX = "pos_friendly"
|
||||
_hbaseRecordQFriendlyNegX = "neg_friendly"
|
||||
_hbaseRecordQCreativityPosX = "pos_creativity"
|
||||
_hbaseRecordQCreativityNegX = "neg_creativity"
|
||||
_hbaseRecordQBountyPosX = "pos_bounty"
|
||||
_hbaseRecordQBountyNegX = "neg_bounty"
|
||||
// UserInfo
|
||||
_hbaseUserTable = "ugc:figureuserstatus"
|
||||
_hbaseUserFC = "user"
|
||||
_hbaseUserQExp = "exp"
|
||||
_hbaseUserQSpy = "spy_score"
|
||||
_hbaseUserQArchiveViews = "archive_views"
|
||||
_hbaseUserQVip = "vip_status"
|
||||
_hbaseUserQDisciplineCommittee = "discipline_committee"
|
||||
// ActionCounter
|
||||
_hbaseActionTable = "ugc:figureactioncounter"
|
||||
_hbaseActionFC = "user"
|
||||
_hbaseActionQCoinCount = "coins"
|
||||
_hbaseActionQReplyCount = "replies"
|
||||
_hbaseActionQDanmakuCount = "danmaku"
|
||||
_hbaseActionQCoinLowRisk = "coin_low_risk"
|
||||
_hbaseActionQCoinHighRisk = "coin_high_risk"
|
||||
_hbaseActionQReplyLowRisk = "reply_low_risk"
|
||||
_hbaseActionQReplyHighRisk = "reply_high_risk"
|
||||
_hbaseActionQReplyLiked = "reply_liked"
|
||||
_hbaseActionQReplyUnLiked = "reply_hate"
|
||||
|
||||
_hbaseActionQReportReplyPassed = "report_reply_passed"
|
||||
_hbaseActionQReportDanmakuPassed = "report_danmaku_passed"
|
||||
_hbaseActionQPublishReplyDeleted = "publish_reply_deleted"
|
||||
_hbaseActionQPublishDanmakuDeleted = "publish_danmaku_deleted"
|
||||
_hbaseActionQPayMoney = "pay_money"
|
||||
_hbaseActionQPayLiveMoney = "pay_live_money"
|
||||
)
|
||||
|
||||
func rowKeyFigureRecord(mid int64, weekTS int64) (key string) {
|
||||
return fmt.Sprintf("%d_%d", mid, weekTS)
|
||||
}
|
||||
|
||||
func rowKeyUserInfo(mid int64) (key string) {
|
||||
return fmt.Sprintf("%d", mid)
|
||||
}
|
||||
|
||||
func rowKeyActionCounter(mid int64, dayTS int64) (key string) {
|
||||
return fmt.Sprintf("%d_%d", mid, dayTS)
|
||||
}
|
||||
|
||||
// UserInfo get it from hbase
|
||||
func (d *Dao) UserInfo(c context.Context, mid int64, weekVer int64) (userInfo *model.UserInfo, err error) {
|
||||
var (
|
||||
result *hrpc.Result
|
||||
key = rowKeyUserInfo(mid)
|
||||
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.Hbase.ReadTimeout))
|
||||
)
|
||||
defer cancel()
|
||||
if result, err = d.hbase.GetStr(ctx, _hbaseUserTable, key); err != nil {
|
||||
err = errors.Wrapf(err, "hbase.GetStr(%s,%s)", _hbaseUserTable, key)
|
||||
return
|
||||
}
|
||||
userInfo = &model.UserInfo{Mid: mid, SpyScore: math.MaxUint64}
|
||||
for _, c := range result.Cells {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
if bytes.Equal([]byte(_hbaseUserFC), c.Family) {
|
||||
switch string(c.Qualifier) {
|
||||
case _hbaseUserQExp:
|
||||
userInfo.Exp = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseUserQSpy:
|
||||
userInfo.SpyScore = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseUserQArchiveViews:
|
||||
userInfo.ArchiveViews = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseUserQVip:
|
||||
userInfo.VIPStatus = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseUserQDisciplineCommittee:
|
||||
userInfo.DisciplineCommittee = binary.BigEndian.Uint16(c.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 未获取到spy分值特殊处理
|
||||
if userInfo.SpyScore == math.MaxUint64 {
|
||||
userInfo.SpyScore = 100
|
||||
}
|
||||
log.Info("User Info [%+v]", userInfo)
|
||||
return
|
||||
}
|
||||
|
||||
// PutCalcRecord put record all the params x.
|
||||
func (d *Dao) PutCalcRecord(c context.Context, record *model.FigureRecord, weekTS int64) (err error) {
|
||||
var (
|
||||
key = rowKeyFigureRecord(record.Mid, weekTS)
|
||||
lawfulPosX = make([]byte, 8)
|
||||
lawfulNegX = make([]byte, 8)
|
||||
widePosX = make([]byte, 8)
|
||||
wideNegX = make([]byte, 8)
|
||||
friendlyPosX = make([]byte, 8)
|
||||
friendlyNegX = make([]byte, 8)
|
||||
creativityPosX = make([]byte, 8)
|
||||
creativityNegX = make([]byte, 8)
|
||||
bountyPosX = make([]byte, 8)
|
||||
bountyNegX = make([]byte, 8)
|
||||
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.Hbase.WriteTimeout))
|
||||
)
|
||||
defer cancel()
|
||||
binary.BigEndian.PutUint64(lawfulPosX, uint64(record.XPosLawful))
|
||||
binary.BigEndian.PutUint64(lawfulNegX, uint64(record.XNegLawful))
|
||||
binary.BigEndian.PutUint64(widePosX, uint64(record.XPosWide))
|
||||
binary.BigEndian.PutUint64(wideNegX, uint64(record.XNegWide))
|
||||
binary.BigEndian.PutUint64(friendlyPosX, uint64(record.XPosFriendly))
|
||||
binary.BigEndian.PutUint64(friendlyNegX, uint64(record.XNegFriendly))
|
||||
binary.BigEndian.PutUint64(creativityPosX, uint64(record.XPosCreativity))
|
||||
binary.BigEndian.PutUint64(creativityNegX, uint64(record.XNegCreativity))
|
||||
binary.BigEndian.PutUint64(bountyPosX, uint64(record.XPosBounty))
|
||||
binary.BigEndian.PutUint64(bountyNegX, uint64(record.XNegBounty))
|
||||
values := map[string]map[string][]byte{_hbaseRecordFC: {
|
||||
_hbaseRecordQLawfulPosX: lawfulPosX,
|
||||
_hbaseRecordQLawfulNegX: lawfulNegX,
|
||||
_hbaseRecordQWideNegX: wideNegX,
|
||||
_hbaseRecordQFriendlyPosX: friendlyPosX,
|
||||
_hbaseRecordQFriendlyNegX: friendlyNegX,
|
||||
_hbaseRecordQCreativityPosX: creativityPosX,
|
||||
_hbaseRecordQCreativityNegX: creativityNegX,
|
||||
_hbaseRecordQBountyPosX: bountyPosX,
|
||||
_hbaseRecordQBountyNegX: bountyNegX,
|
||||
}}
|
||||
if _, err = d.hbase.PutStr(ctx, _hbaseRecordTable, key, values); err != nil {
|
||||
err = errors.Wrapf(err, "hbase.Put(%s,%s,%+v) error(%v)", _hbaseRecordTable, key, values, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CalcRecords get it from hbase
|
||||
func (d *Dao) CalcRecords(c context.Context, mid int64, weekTSFrom, weekTSTo int64) (figureRecords []*model.FigureRecord, err error) {
|
||||
var (
|
||||
scanner hrpc.Scanner
|
||||
keyFrom = rowKeyFigureRecord(mid, weekTSFrom)
|
||||
keyTo = rowKeyFigureRecord(mid, weekTSTo)
|
||||
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.Hbase.ReadTimeout))
|
||||
)
|
||||
defer cancel()
|
||||
if scanner, err = d.hbase.ScanRangeStr(ctx, _hbaseRecordTable, keyFrom, keyTo); err != nil {
|
||||
err = errors.Wrapf(err, "hbase.ScanRangeStr(%s,%s,%s)", _hbaseRecordTable, keyFrom, keyTo)
|
||||
return
|
||||
}
|
||||
for {
|
||||
res, err := scanner.Next()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
err = errors.WithStack(err)
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
figureRecord := &model.FigureRecord{Mid: mid}
|
||||
for i, c := range res.Cells {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
if bytes.Equal([]byte(_hbaseRecordFC), c.Family) {
|
||||
switch string(c.Qualifier) {
|
||||
case _hbaseRecordQLawfulPosX:
|
||||
figureRecord.XPosLawful = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQLawfulNegX:
|
||||
figureRecord.XNegLawful = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQWidePosX:
|
||||
figureRecord.XPosWide = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQWideNegX:
|
||||
figureRecord.XNegWide = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQFriendlyPosX:
|
||||
figureRecord.XPosFriendly = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQFriendlyNegX:
|
||||
figureRecord.XNegFriendly = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQCreativityPosX:
|
||||
figureRecord.XPosCreativity = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQCreativityNegX:
|
||||
figureRecord.XNegCreativity = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQBountyPosX:
|
||||
figureRecord.XPosBounty = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseRecordQBountyNegX:
|
||||
figureRecord.XNegBounty = int64(binary.BigEndian.Uint64(c.Value))
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
figureRecord.Version = time.Unix(parseVersion(string(c.Row), c.Timestamp), 0)
|
||||
}
|
||||
}
|
||||
log.Info("User figure record [%+v]", figureRecord)
|
||||
figureRecords = append(figureRecords, figureRecord)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ActionCounter .
|
||||
func (d *Dao) ActionCounter(c context.Context, mid int64, ts int64) (actionCounter *model.ActionCounter, err error) {
|
||||
var (
|
||||
result *hrpc.Result
|
||||
key = rowKeyActionCounter(mid, ts)
|
||||
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.Hbase.ReadTimeout))
|
||||
)
|
||||
defer cancel()
|
||||
log.Info("Get mid [%d] key [%s]", mid, key)
|
||||
if result, err = d.hbase.GetStr(ctx, _hbaseActionTable, key); err != nil {
|
||||
err = errors.Wrapf(err, "hbase.GetStr(%s,%s)", _hbaseActionTable, key)
|
||||
return
|
||||
}
|
||||
actionCounter = &model.ActionCounter{Mid: mid}
|
||||
for i, c := range result.Cells {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
if bytes.Equal([]byte(_hbaseActionFC), c.Family) {
|
||||
switch string(c.Qualifier) {
|
||||
case _hbaseActionQCoinCount:
|
||||
actionCounter.CoinCount = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseActionQReplyCount:
|
||||
actionCounter.ReplyCount = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQDanmakuCount:
|
||||
actionCounter.DanmakuCount = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQCoinLowRisk:
|
||||
actionCounter.CoinLowRisk = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseActionQCoinHighRisk:
|
||||
actionCounter.CoinHighRisk = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseActionQReplyLowRisk:
|
||||
actionCounter.ReplyLowRisk = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseActionQReplyHighRisk:
|
||||
actionCounter.ReplyHighRisk = binary.BigEndian.Uint64(c.Value)
|
||||
case _hbaseActionQReplyLiked:
|
||||
actionCounter.ReplyLiked = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQReplyUnLiked:
|
||||
actionCounter.ReplyUnliked = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQReportReplyPassed:
|
||||
actionCounter.ReportReplyPassed = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQReportDanmakuPassed:
|
||||
actionCounter.ReportDanmakuPassed = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQPublishReplyDeleted:
|
||||
actionCounter.PublishReplyDeleted = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQPublishDanmakuDeleted:
|
||||
actionCounter.PublishDanmakuDeleted = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQPayMoney:
|
||||
actionCounter.PayMoney = int64(binary.BigEndian.Uint64(c.Value))
|
||||
case _hbaseActionQPayLiveMoney:
|
||||
actionCounter.PayLiveMoney = int64(binary.BigEndian.Uint64(c.Value))
|
||||
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
actionCounter.Version = time.Unix(parseVersion(string(c.Row), c.Timestamp), 0)
|
||||
}
|
||||
}
|
||||
log.Info("User action counter [%+v]", actionCounter)
|
||||
return
|
||||
}
|
||||
|
||||
// // ActionCounters .
|
||||
// func (d *Dao) ActionCounters(c context.Context, mid int64, tsfrom int64, tsto int64) (actionCounters []*model.ActionCounter, err error) {
|
||||
// var (
|
||||
// scan *hrpc.Scan
|
||||
// results []*hrpc.Result
|
||||
// keyFrom = rowKeyActionCounter(mid, tsfrom)
|
||||
// keyTo = rowKeyActionCounter(mid, tsto)
|
||||
// ctx, cancel = context.WithTimeout(c, time.Duration(d.c.Hbase.ReadTimeout))
|
||||
// )
|
||||
// defer cancel()
|
||||
// log.Info("Scan mid [%d] keyFrom [%s] keyTo [%s]", mid, keyFrom, keyTo)
|
||||
// if scan, err = hrpc.NewScanRangeStr(ctx, _hbaseActionTable, keyFrom, keyTo); err != nil {
|
||||
// err = errors.Wrapf(err, "hrcp.NewScanRangeStr(%s,%s,%s)", _hbaseActionTable, keyFrom, keyTo)
|
||||
// return
|
||||
// }
|
||||
// if results, err = d.hbase.Scan(ctx, scan); err != nil {
|
||||
// err = errors.Wrapf(err, "hbase.Scan(%s,%s,%s)", _hbaseActionTable, keyFrom, keyTo)
|
||||
// return
|
||||
// }
|
||||
// if len(results) == 0 {
|
||||
// return
|
||||
// }
|
||||
// for _, res := range results {
|
||||
// if res == nil {
|
||||
// continue
|
||||
// }
|
||||
// actionCounter := &model.ActionCounter{Mid: mid}
|
||||
// for i, c := range res.Cells {
|
||||
// if c == nil {
|
||||
// continue
|
||||
// }
|
||||
// if bytes.Equal([]byte(_hbaseActionFC), c.Family) {
|
||||
// switch string(c.Qualifier) {
|
||||
// case _hbaseActionQCoinCount:
|
||||
// actionCounter.CoinCount = binary.BigEndian.Uint64(c.Value)
|
||||
// case _hbaseActionQReplyCount:
|
||||
// actionCounter.ReplyCount = int64(binary.BigEndian.Uint64(c.Value))
|
||||
// case _hbaseActionQCoinLowRisk:
|
||||
// actionCounter.CoinLowRisk = binary.BigEndian.Uint64(c.Value)
|
||||
// case _hbaseActionQCoinHighRisk:
|
||||
// actionCounter.CoinHighRisk = binary.BigEndian.Uint64(c.Value)
|
||||
// case _hbaseActionQReplyLowRisk:
|
||||
// actionCounter.ReplyLowRisk = binary.BigEndian.Uint64(c.Value)
|
||||
// case _hbaseActionQReplyHighRisk:
|
||||
// actionCounter.ReplyHighRisk = binary.BigEndian.Uint64(c.Value)
|
||||
// case _hbaseActionQReplyLiked:
|
||||
// actionCounter.ReplyLiked = int64(binary.BigEndian.Uint64(c.Value))
|
||||
// case _hbaseActionQReplyUnLiked:
|
||||
// actionCounter.ReplyUnliked = int64(binary.BigEndian.Uint64(c.Value))
|
||||
// }
|
||||
// }
|
||||
// if i == 0 {
|
||||
// actionCounter.Version = time.Unix(parseVersion(string(c.Row), c.Timestamp), 0)
|
||||
// }
|
||||
// }
|
||||
// log.Info("User action counter [%+v]", actionCounter)
|
||||
// actionCounters = append(actionCounters, actionCounter)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func parseVersion(rowKey string, timestamp *uint64) (ts int64) {
|
||||
strs := strings.Split(rowKey, "_")
|
||||
if len(strs) < 2 {
|
||||
return int64(*timestamp)
|
||||
}
|
||||
var err error
|
||||
if ts, err = strconv.ParseInt(strs[1], 10, 64); err != nil {
|
||||
return int64(*timestamp)
|
||||
}
|
||||
return ts
|
||||
}
|
42
app/job/main/figure-timer/dao/mock_dao/BUILD
Normal file
42
app/job/main/figure-timer/dao/mock_dao/BUILD
Normal file
@ -0,0 +1,42 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_test",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["mock_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
rundir = ".",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["mock.go"],
|
||||
importpath = "go-common/app/job/main/figure-timer/dao/mock_dao",
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//app/job/main/figure-timer/model:go_default_library",
|
||||
"//vendor/github.com/golang/mock/gomock: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"],
|
||||
)
|
225
app/job/main/figure-timer/dao/mock_dao/mock.go
Normal file
225
app/job/main/figure-timer/dao/mock_dao/mock.go
Normal file
@ -0,0 +1,225 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: go-common/app/job/main/figure-timer/dao (interfaces: DaoInt)
|
||||
|
||||
// Package mock_dao is a generated GoMock package.
|
||||
package mock_dao
|
||||
|
||||
import (
|
||||
context "context"
|
||||
model "go-common/app/job/main/figure-timer/model"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockDaoInt is a mock of DaoInt interface
|
||||
type MockDaoInt struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDaoIntMockRecorder
|
||||
}
|
||||
|
||||
// MockDaoIntMockRecorder is the mock recorder for MockDaoInt
|
||||
type MockDaoIntMockRecorder struct {
|
||||
mock *MockDaoInt
|
||||
}
|
||||
|
||||
// NewMockDaoInt creates a new mock instance
|
||||
func NewMockDaoInt(ctrl *gomock.Controller) *MockDaoInt {
|
||||
mock := &MockDaoInt{ctrl: ctrl}
|
||||
mock.recorder = &MockDaoIntMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockDaoInt) EXPECT() *MockDaoIntMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ActionCounter mocks base method
|
||||
func (m *MockDaoInt) ActionCounter(arg0 context.Context, arg1, arg2 int64) (*model.ActionCounter, error) {
|
||||
ret := m.ctrl.Call(m, "ActionCounter", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*model.ActionCounter)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ActionCounter indicates an expected call of ActionCounter
|
||||
func (mr *MockDaoIntMockRecorder) ActionCounter(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActionCounter", reflect.TypeOf((*MockDaoInt)(nil).ActionCounter), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CalcRecords mocks base method
|
||||
func (m *MockDaoInt) CalcRecords(arg0 context.Context, arg1, arg2, arg3 int64) ([]*model.FigureRecord, error) {
|
||||
ret := m.ctrl.Call(m, "CalcRecords", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].([]*model.FigureRecord)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CalcRecords indicates an expected call of CalcRecords
|
||||
func (mr *MockDaoIntMockRecorder) CalcRecords(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalcRecords", reflect.TypeOf((*MockDaoInt)(nil).CalcRecords), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Close mocks base method
|
||||
func (m *MockDaoInt) Close() {
|
||||
m.ctrl.Call(m, "Close")
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close
|
||||
func (mr *MockDaoIntMockRecorder) Close() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDaoInt)(nil).Close))
|
||||
}
|
||||
|
||||
// Figure mocks base method
|
||||
func (m *MockDaoInt) Figure(arg0 context.Context, arg1 int64) (*model.Figure, error) {
|
||||
ret := m.ctrl.Call(m, "Figure", arg0, arg1)
|
||||
ret0, _ := ret[0].(*model.Figure)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Figure indicates an expected call of Figure
|
||||
func (mr *MockDaoIntMockRecorder) Figure(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Figure", reflect.TypeOf((*MockDaoInt)(nil).Figure), arg0, arg1)
|
||||
}
|
||||
|
||||
// FigureCache mocks base method
|
||||
func (m *MockDaoInt) FigureCache(arg0 context.Context, arg1 int64) (*model.Figure, error) {
|
||||
ret := m.ctrl.Call(m, "FigureCache", arg0, arg1)
|
||||
ret0, _ := ret[0].(*model.Figure)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FigureCache indicates an expected call of FigureCache
|
||||
func (mr *MockDaoIntMockRecorder) FigureCache(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FigureCache", reflect.TypeOf((*MockDaoInt)(nil).FigureCache), arg0, arg1)
|
||||
}
|
||||
|
||||
// Figures mocks base method
|
||||
func (m *MockDaoInt) Figures(arg0 context.Context, arg1 int64, arg2 int) ([]*model.Figure, bool, error) {
|
||||
ret := m.ctrl.Call(m, "Figures", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]*model.Figure)
|
||||
ret1, _ := ret[1].(bool)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Figures indicates an expected call of Figures
|
||||
func (mr *MockDaoIntMockRecorder) Figures(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Figures", reflect.TypeOf((*MockDaoInt)(nil).Figures), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// InsertRankHistory mocks base method
|
||||
func (m *MockDaoInt) InsertRankHistory(arg0 context.Context, arg1 *model.Rank) (int64, error) {
|
||||
ret := m.ctrl.Call(m, "InsertRankHistory", arg0, arg1)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// InsertRankHistory indicates an expected call of InsertRankHistory
|
||||
func (mr *MockDaoIntMockRecorder) InsertRankHistory(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertRankHistory", reflect.TypeOf((*MockDaoInt)(nil).InsertRankHistory), arg0, arg1)
|
||||
}
|
||||
|
||||
// PendingMidsCache mocks base method
|
||||
func (m *MockDaoInt) PendingMidsCache(arg0 context.Context, arg1, arg2 int64) ([]int64, error) {
|
||||
ret := m.ctrl.Call(m, "PendingMidsCache", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PendingMidsCache indicates an expected call of PendingMidsCache
|
||||
func (mr *MockDaoIntMockRecorder) PendingMidsCache(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PendingMidsCache", reflect.TypeOf((*MockDaoInt)(nil).PendingMidsCache), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Ping mocks base method
|
||||
func (m *MockDaoInt) Ping(arg0 context.Context) error {
|
||||
ret := m.ctrl.Call(m, "Ping", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Ping indicates an expected call of Ping
|
||||
func (mr *MockDaoIntMockRecorder) Ping(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockDaoInt)(nil).Ping), arg0)
|
||||
}
|
||||
|
||||
// PutCalcRecord mocks base method
|
||||
func (m *MockDaoInt) PutCalcRecord(arg0 context.Context, arg1 *model.FigureRecord, arg2 int64) error {
|
||||
ret := m.ctrl.Call(m, "PutCalcRecord", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PutCalcRecord indicates an expected call of PutCalcRecord
|
||||
func (mr *MockDaoIntMockRecorder) PutCalcRecord(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutCalcRecord", reflect.TypeOf((*MockDaoInt)(nil).PutCalcRecord), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// RemoveCache mocks base method
|
||||
func (m *MockDaoInt) RemoveCache(arg0 context.Context, arg1 int64) error {
|
||||
ret := m.ctrl.Call(m, "RemoveCache", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RemoveCache indicates an expected call of RemoveCache
|
||||
func (mr *MockDaoIntMockRecorder) RemoveCache(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveCache", reflect.TypeOf((*MockDaoInt)(nil).RemoveCache), arg0, arg1)
|
||||
}
|
||||
|
||||
// SetFigureCache mocks base method
|
||||
func (m *MockDaoInt) SetFigureCache(arg0 context.Context, arg1 *model.Figure) error {
|
||||
ret := m.ctrl.Call(m, "SetFigureCache", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetFigureCache indicates an expected call of SetFigureCache
|
||||
func (mr *MockDaoIntMockRecorder) SetFigureCache(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFigureCache", reflect.TypeOf((*MockDaoInt)(nil).SetFigureCache), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpsertFigure mocks base method
|
||||
func (m *MockDaoInt) UpsertFigure(arg0 context.Context, arg1 *model.Figure) (int64, error) {
|
||||
ret := m.ctrl.Call(m, "UpsertFigure", arg0, arg1)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpsertFigure indicates an expected call of UpsertFigure
|
||||
func (mr *MockDaoIntMockRecorder) UpsertFigure(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertFigure", reflect.TypeOf((*MockDaoInt)(nil).UpsertFigure), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpsertRank mocks base method
|
||||
func (m *MockDaoInt) UpsertRank(arg0 context.Context, arg1 *model.Rank) (int64, error) {
|
||||
ret := m.ctrl.Call(m, "UpsertRank", arg0, arg1)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpsertRank indicates an expected call of UpsertRank
|
||||
func (mr *MockDaoIntMockRecorder) UpsertRank(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertRank", reflect.TypeOf((*MockDaoInt)(nil).UpsertRank), arg0, arg1)
|
||||
}
|
||||
|
||||
// UserInfo mocks base method
|
||||
func (m *MockDaoInt) UserInfo(arg0 context.Context, arg1, arg2 int64) (*model.UserInfo, error) {
|
||||
ret := m.ctrl.Call(m, "UserInfo", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*model.UserInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UserInfo indicates an expected call of UserInfo
|
||||
func (mr *MockDaoIntMockRecorder) UserInfo(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserInfo", reflect.TypeOf((*MockDaoInt)(nil).UserInfo), arg0, arg1, arg2)
|
||||
}
|
13
app/job/main/figure-timer/dao/mock_dao/mock_test.go
Normal file
13
app/job/main/figure-timer/dao/mock_dao/mock_test.go
Normal file
@ -0,0 +1,13 @@
|
||||
package mock_dao
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestFake(t *testing.T) {
|
||||
Convey("Test fake", t, func() {
|
||||
t.Log("nothing here")
|
||||
})
|
||||
}
|
119
app/job/main/figure-timer/dao/mysql.go
Normal file
119
app/job/main/figure-timer/dao/mysql.go
Normal file
@ -0,0 +1,119 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
xsql "go-common/library/database/sql"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
_shard = 100
|
||||
_selFigure = `SELECT id,mid,score,lawful_score,wide_score,friendly_score,bounty_score,creativity_score,ver,ctime,mtime FROM figure_user_%02d WHERE mid=? LIMIT 1`
|
||||
_selFigures = `SELECT id,mid,score,lawful_score,wide_score,friendly_score,bounty_score,creativity_score,ver,ctime,mtime FROM figure_user_%02d WHERE mid>? LIMIT ?`
|
||||
_upsertFigure = `INSERT INTO figure_user_%02d (mid,score,lawful_score,wide_score,friendly_score,bounty_score,creativity_score,ver,ctime,mtime) VALUES (?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE score=?,lawful_score=?,wide_score=?,friendly_score=?,bounty_score=?,creativity_score=?,ver=?,mtime=?`
|
||||
_insertRank = `INSERT INTO figure_rank (score_from,score_to,percentage) VALUES(?,?,?) ON DUPLICATE KEY UPDATE score_from=?,score_to=?,percentage=?`
|
||||
_insertRankHistory = `INSERT INTO figure_rank_history (score_from,score_to,percentage,ver) VALUES(?,?,?,?)`
|
||||
)
|
||||
|
||||
func hit(mid int64) int64 {
|
||||
return mid % _shard
|
||||
}
|
||||
|
||||
// Figure get Figure from db
|
||||
func (d *Dao) Figure(c context.Context, mid int64) (figure *model.Figure, err error) {
|
||||
row := d.mysql.QueryRow(c, fmt.Sprintf(_selFigure, hit(mid)), mid)
|
||||
figure = &model.Figure{}
|
||||
if err = row.Scan(&figure.ID, &figure.Mid, &figure.Score, &figure.LawfulScore, &figure.WideScore, &figure.FriendlyScore, &figure.BountyScore, &figure.CreativityScore, &figure.Ver, &figure.Ctime, &figure.Mtime); err != nil {
|
||||
if err == xsql.ErrNoRows {
|
||||
err = nil
|
||||
figure = nil
|
||||
return
|
||||
}
|
||||
err = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Figures get all figure info from formMid
|
||||
func (d *Dao) Figures(c context.Context, fromMid int64, limit int) (figures []*model.Figure, end bool, err error) {
|
||||
if limit <= 0 {
|
||||
return
|
||||
}
|
||||
var (
|
||||
rows *xsql.Rows
|
||||
)
|
||||
if rows, err = d.mysql.Query(c, fmt.Sprintf(_selFigures, hit(fromMid)), fromMid, limit); err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
figure := &model.Figure{}
|
||||
if err = rows.Scan(&figure.ID, &figure.Mid, &figure.Score, &figure.LawfulScore, &figure.WideScore, &figure.FriendlyScore, &figure.BountyScore, &figure.CreativityScore, &figure.Ver, &figure.Ctime, &figure.Mtime); err != nil {
|
||||
if err == xsql.ErrNoRows {
|
||||
err = nil
|
||||
end = true
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
figures = append(figures, figure)
|
||||
}
|
||||
if len(figures) < limit {
|
||||
end = true
|
||||
}
|
||||
err = errors.WithStack(rows.Err())
|
||||
return
|
||||
}
|
||||
|
||||
// UpsertFigure insert or update(if mid duplicated) Figure
|
||||
func (d *Dao) UpsertFigure(c context.Context, figure *model.Figure) (id int64, err error) {
|
||||
var (
|
||||
result sql.Result
|
||||
now = time.Now()
|
||||
)
|
||||
if result, err = d.mysql.Exec(c, fmt.Sprintf(_upsertFigure, hit(figure.Mid)), figure.Mid, figure.Score, figure.LawfulScore, figure.WideScore, figure.FriendlyScore, figure.BountyScore, figure.CreativityScore, figure.Ver, now, now, figure.Score, figure.LawfulScore, figure.WideScore, figure.FriendlyScore, figure.BountyScore, figure.CreativityScore, figure.Ver, now); err != nil {
|
||||
return
|
||||
}
|
||||
if id, err = result.LastInsertId(); err != nil {
|
||||
err = errors.WithStack(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// InsertRankHistory insert figure rank history to db
|
||||
func (d *Dao) InsertRankHistory(c context.Context, rank *model.Rank) (id int64, err error) {
|
||||
var (
|
||||
res sql.Result
|
||||
)
|
||||
if res, err = d.mysql.Exec(c, _insertRankHistory, rank.ScoreFrom, rank.ScoreTo, rank.Percentage, rank.Ver); err != nil {
|
||||
return
|
||||
}
|
||||
if id, err = res.LastInsertId(); err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpsertRank insert or update figure rank to db
|
||||
func (d *Dao) UpsertRank(c context.Context, rank *model.Rank) (id int64, err error) {
|
||||
var (
|
||||
res sql.Result
|
||||
)
|
||||
if res, err = d.mysql.Exec(c, _insertRank, rank.ScoreFrom, rank.ScoreTo, rank.Percentage, rank.ScoreFrom, rank.ScoreTo, rank.Percentage); err != nil {
|
||||
return
|
||||
}
|
||||
if id, err = res.LastInsertId(); err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
99
app/job/main/figure-timer/dao/redis.go
Normal file
99
app/job/main/figure-timer/dao/redis.go
Normal file
@ -0,0 +1,99 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/cache/redis"
|
||||
"go-common/library/log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func keyFigure(mid int64) string {
|
||||
return fmt.Sprintf("f:%d", mid)
|
||||
}
|
||||
|
||||
func keyPendingMids(ver int64, shard int64) string {
|
||||
return fmt.Sprintf("w:u%d%d", ver, shard)
|
||||
}
|
||||
|
||||
// PingRedis check redis connection
|
||||
func (d *Dao) PingRedis(c context.Context) (err error) {
|
||||
conn := d.redis.Get(c)
|
||||
defer conn.Close()
|
||||
_, err = conn.Do("SET", "PING", "PONG")
|
||||
return
|
||||
}
|
||||
|
||||
// FigureCache get FigureUser from cache
|
||||
func (d *Dao) FigureCache(c context.Context, mid int64) (figure *model.Figure, err error) {
|
||||
key := keyFigure(mid)
|
||||
conn := d.redis.Get(c)
|
||||
defer conn.Close()
|
||||
item, err := redis.Bytes(conn.Do("GET", key))
|
||||
if err != nil {
|
||||
if err == redis.ErrNil {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
figure = &model.Figure{}
|
||||
if err = json.Unmarshal(item, &figure); err != nil {
|
||||
log.Error("json.Unmarshal(%v) err(%v)", item, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetFigureCache set FigureUser to cache
|
||||
func (d *Dao) SetFigureCache(c context.Context, figure *model.Figure) (err error) {
|
||||
key := keyFigure(figure.Mid)
|
||||
conn := d.redis.Get(c)
|
||||
defer conn.Close()
|
||||
values, err := json.Marshal(figure)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = conn.Send("SET", key, values); err != nil {
|
||||
log.Error("conn.Send(SET, %s, %v) error(%v)", key, values, err)
|
||||
return
|
||||
}
|
||||
if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
|
||||
log.Error("conn.Send(Expire, %s, %d) error(%v)", key, d.redisExpire, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PendingMidsCache get PendingUser set from cache
|
||||
func (d *Dao) PendingMidsCache(c context.Context, version int64, shard int64) (mids []int64, err error) {
|
||||
var (
|
||||
conn = d.redis.Get(c)
|
||||
key = keyPendingMids(version, shard)
|
||||
)
|
||||
defer conn.Close()
|
||||
if mids, err = redis.Int64s(conn.Do("SMEMBERS", key)); err != nil {
|
||||
if err == redis.ErrNil {
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
err = errors.Wrapf(err, "redis.Int64s(conn.Do(SMEMEBERS,%s))", key)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveCache remove figure cache
|
||||
func (d *Dao) RemoveCache(c context.Context, mid int64) (err error) {
|
||||
key := keyFigure(mid)
|
||||
conn := d.redis.Get(c)
|
||||
defer conn.Close()
|
||||
|
||||
if err = conn.Send("DEL", key); err != nil {
|
||||
log.Error("conn.Send(DEL, %s) error(%v)", key, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
40
app/job/main/figure-timer/db.sql
Normal file
40
app/job/main/figure-timer/db.sql
Normal file
@ -0,0 +1,40 @@
|
||||
CREATE TABLE `figure_user_[00-99]` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户信用分模型',
|
||||
`mid` int(11) NOT NULL COMMENT '用户mid',
|
||||
`score` smallint(6) NOT NULL DEFAULT '0' COMMENT '信用分值',
|
||||
`lawful_score` smallint(6) NOT NULL DEFAULT '0' COMMENT '守序',
|
||||
`wide_score` smallint(6) NOT NULL DEFAULT '0' COMMENT '博览',
|
||||
`friendly_score` smallint(6) NOT NULL DEFAULT '0' COMMENT '友爱',
|
||||
`bounty_score` smallint(6) NOT NULL DEFAULT '0' COMMENT '慷慨',
|
||||
`creativity_score` smallint(6) NOT NULL DEFAULT '0' COMMENT '创造',
|
||||
`ver` int(11) NOT NULL DEFAULT '0' COMMENT '版本',
|
||||
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创造世界',
|
||||
`mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_mid` (`mid`),
|
||||
KEY `ix_mtime` (`mtime`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=697525 DEFAULT CHARSET=utf8 COMMENT='信用用户表';
|
||||
|
||||
CREATE TABLE `figure_rank` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`score_from` smallint(6) NOT NULL DEFAULT '0' COMMENT '起始分段分值,包含',
|
||||
`score_to` smallint(6) NOT NULL DEFAULT '0' COMMENT '结束分段分值,包含',
|
||||
`percentage` smallint(6) NOT NULL DEFAULT '0' COMMENT '排名百分比',
|
||||
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_percentage` (`percentage`),
|
||||
KEY `ix_mtime` (`mtime`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='当前信用分排名表'
|
||||
|
||||
CREATE TABLE `figure_rank_history` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
|
||||
`score_from` smallint(6) NOT NULL DEFAULT '0' COMMENT '起始分段分值,包含',
|
||||
`score_to` smallint(6) NOT NULL DEFAULT '0' COMMENT '结束分段分值,包含',
|
||||
`percentage` smallint(6) NOT NULL DEFAULT '0' COMMENT '排名百分比',
|
||||
`ver` int(11) NOT NULL DEFAULT '0' COMMENT '版本',
|
||||
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ix_mtime` (`mtime`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='信用分历史排名表';
|
34
app/job/main/figure-timer/http/BUILD
Normal file
34
app/job/main/figure-timer/http/BUILD
Normal file
@ -0,0 +1,34 @@
|
||||
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/figure-timer/http",
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//app/job/main/figure-timer/conf:go_default_library",
|
||||
"//app/job/main/figure-timer/service:go_default_library",
|
||||
"//library/log:go_default_library",
|
||||
"//library/net/http/blademaster: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"],
|
||||
)
|
37
app/job/main/figure-timer/http/http.go
Normal file
37
app/job/main/figure-timer/http/http.go
Normal file
@ -0,0 +1,37 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/service"
|
||||
"go-common/library/log"
|
||||
bm "go-common/library/net/http/blademaster"
|
||||
)
|
||||
|
||||
var (
|
||||
svc *service.Service
|
||||
)
|
||||
|
||||
// Init init a http server
|
||||
func Init(s *service.Service) {
|
||||
svc = s
|
||||
|
||||
e := bm.DefaultServer(conf.Conf.BM)
|
||||
innerRouter(e)
|
||||
if err := e.Start(); err != nil {
|
||||
log.Error("%+v", err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// innerRouter init inner router.
|
||||
func innerRouter(e *bm.Engine) {
|
||||
e.Ping(ping)
|
||||
}
|
||||
|
||||
// ping check server ok.
|
||||
func ping(c *bm.Context) {
|
||||
// if err := svc.Ping(c); err != nil {
|
||||
// log.Error("figure-timer-job ping err (%+v)", err)
|
||||
// c.AbortWithStatus(http.StatusServiceUnavailable)
|
||||
// }
|
||||
}
|
31
app/job/main/figure-timer/model/BUILD
Normal file
31
app/job/main/figure-timer/model/BUILD
Normal 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 = [
|
||||
"db.go",
|
||||
"hbase.go",
|
||||
],
|
||||
importpath = "go-common/app/job/main/figure-timer/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"],
|
||||
)
|
29
app/job/main/figure-timer/model/db.go
Normal file
29
app/job/main/figure-timer/model/db.go
Normal file
@ -0,0 +1,29 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// Figure user figure model
|
||||
type Figure struct {
|
||||
ID int64 `json:"-"`
|
||||
Mid int64 `json:"mid"`
|
||||
Score int32 `json:"score"`
|
||||
LawfulScore int32 `json:"lawful_score"`
|
||||
WideScore int32 `json:"wide_score"`
|
||||
FriendlyScore int32 `json:"friendly_score"`
|
||||
BountyScore int32 `json:"bounty_score"`
|
||||
CreativityScore int32 `json:"creativity_score"`
|
||||
Ver int64 `json:"-"`
|
||||
Ctime time.Time `json:"-"`
|
||||
Mtime time.Time `json:"-"`
|
||||
}
|
||||
|
||||
// Rank rank fiigure
|
||||
type Rank struct {
|
||||
ID int64 `json:"-"`
|
||||
ScoreFrom int32 `json:"score_from"`
|
||||
ScoreTo int32 `json:"score_to"`
|
||||
Percentage int8 `json:"percentage"`
|
||||
Ver int64 `json:"ver"`
|
||||
Ctime time.Time `json:"-"`
|
||||
Mtime time.Time `json:"-"`
|
||||
}
|
49
app/job/main/figure-timer/model/hbase.go
Normal file
49
app/job/main/figure-timer/model/hbase.go
Normal file
@ -0,0 +1,49 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type FigureRecord struct {
|
||||
Mid int64
|
||||
XPosLawful int64
|
||||
XNegLawful int64
|
||||
XPosWide int64
|
||||
XNegWide int64
|
||||
XPosFriendly int64
|
||||
XNegFriendly int64
|
||||
XPosCreativity int64
|
||||
XNegCreativity int64
|
||||
XPosBounty int64
|
||||
XNegBounty int64
|
||||
Version time.Time
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
Mid int64
|
||||
Exp uint64 // 当周期最终经验值
|
||||
SpyScore uint64 // spy得分
|
||||
ArchiveViews uint64 // 观看视频累计天使
|
||||
VIPStatus uint64 // VIP状态
|
||||
DisciplineCommittee uint16 // 风纪委得分
|
||||
}
|
||||
|
||||
type ActionCounter struct {
|
||||
Mid int64
|
||||
CoinCount uint64 // 投币行为数
|
||||
ReplyCount int64 // 评论次数
|
||||
DanmakuCount int64 // 弹幕计次
|
||||
CoinLowRisk uint64 // 投币疑似异常
|
||||
CoinHighRisk uint64 // 投币高危异常
|
||||
ReplyLowRisk uint64 // 评论疑似异常
|
||||
ReplyHighRisk uint64 // 评论高危异常
|
||||
ReplyLiked int64 // 评论被赞数
|
||||
ReplyUnliked int64 // 评论被踩数
|
||||
ReportReplyPassed int64 // 举报评论通过
|
||||
ReportDanmakuPassed int64 // 举报弹幕通过
|
||||
PublishReplyDeleted int64 // 评论被删除
|
||||
PublishDanmakuDeleted int64 // 弹幕被删除
|
||||
PayMoney int64 // 支付消费金额(单位分)
|
||||
PayLiveMoney int64 // 支付消费金额(单位分)
|
||||
Version time.Time
|
||||
}
|
57
app/job/main/figure-timer/service/BUILD
Normal file
57
app/job/main/figure-timer/service/BUILD
Normal file
@ -0,0 +1,57 @@
|
||||
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/figure-timer/conf:go_default_library",
|
||||
"//app/job/main/figure-timer/dao/mock_dao:go_default_library",
|
||||
"//app/job/main/figure-timer/model:go_default_library",
|
||||
"//library/log:go_default_library",
|
||||
"//vendor/github.com/golang/mock/gomock:go_default_library",
|
||||
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"calc.go",
|
||||
"fix.go",
|
||||
"rank.go",
|
||||
"service.go",
|
||||
],
|
||||
importpath = "go-common/app/job/main/figure-timer/service",
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//app/job/main/figure-timer/conf:go_default_library",
|
||||
"//app/job/main/figure-timer/dao:go_default_library",
|
||||
"//app/job/main/figure-timer/model:go_default_library",
|
||||
"//library/log:go_default_library",
|
||||
"//vendor/github.com/robfig/cron: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"],
|
||||
)
|
351
app/job/main/figure-timer/service/calc.go
Normal file
351
app/job/main/figure-timer/service/calc.go
Normal file
@ -0,0 +1,351 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/log"
|
||||
)
|
||||
|
||||
const (
|
||||
bizTypePosLawful = iota
|
||||
bizTypeNegLawful
|
||||
// bizTypePosWide
|
||||
// bizTypeNegWide
|
||||
bizTypePosFriendly
|
||||
bizTypeNegFriendly
|
||||
bizTypePosCreativity
|
||||
// bizTypeNegCreativity
|
||||
bizTypePosBounty
|
||||
// bizTypeNegBounty
|
||||
)
|
||||
|
||||
// HandleFigure handle all figure score for a mid
|
||||
func (s *Service) HandleFigure(c context.Context, mid int64, weekVer int64) (err error) {
|
||||
var (
|
||||
figure = &model.Figure{}
|
||||
userInfo *model.UserInfo
|
||||
actionCounter *model.ActionCounter
|
||||
records []*model.FigureRecord
|
||||
newRecord *model.FigureRecord
|
||||
weekVerRecordsFrom = time.Unix(weekVer, 0).AddDate(0, 0, -7*52).Unix()
|
||||
weekVerRecordsTo = time.Unix(weekVer, 0).AddDate(0, 0, -7).Unix() + 1
|
||||
)
|
||||
//1. get user_info from hbase
|
||||
if userInfo, err = s.dao.UserInfo(c, mid, weekVer); err != nil {
|
||||
return
|
||||
}
|
||||
//2. get action_counter from hbase
|
||||
if actionCounter, err = s.dao.ActionCounter(c, mid, weekVer); err != nil {
|
||||
return
|
||||
}
|
||||
//3. get figure_records from hbase
|
||||
if records, err = s.dao.CalcRecords(c, mid, weekVerRecordsFrom, weekVerRecordsTo); err != nil {
|
||||
return
|
||||
}
|
||||
//4. calc figure
|
||||
figure, newRecord = s.CalcFigure(c, userInfo, []*model.ActionCounter{actionCounter}, records, weekVer)
|
||||
log.Info("User figure [%+v]", figure)
|
||||
log.Info("User newRecord [%+v]", newRecord)
|
||||
//5. save to db
|
||||
time.Sleep(time.Millisecond)
|
||||
if figure.ID, err = s.dao.UpsertFigure(c, figure); err != nil {
|
||||
log.Error("%+v", err)
|
||||
}
|
||||
//6. save new record
|
||||
if err = s.dao.PutCalcRecord(c, newRecord, weekVer); err != nil {
|
||||
log.Error("%+v", err)
|
||||
}
|
||||
//7. remove existed redis
|
||||
if err = s.dao.RemoveCache(c, mid); err != nil {
|
||||
log.Error("%+v", err)
|
||||
}
|
||||
rank.AddScore(figure.Score)
|
||||
return
|
||||
}
|
||||
|
||||
// CalcFigure calc figure.
|
||||
func (s *Service) CalcFigure(c context.Context, userInfo *model.UserInfo, actionCounters []*model.ActionCounter, records []*model.FigureRecord, weekVer int64) (figure *model.Figure, newRecord *model.FigureRecord) {
|
||||
figure = &model.Figure{Mid: userInfo.Mid, Ver: weekVer}
|
||||
newRecord = &model.FigureRecord{Mid: userInfo.Mid, Version: time.Unix(weekVer, 0)}
|
||||
var (
|
||||
posx float64
|
||||
negx float64
|
||||
newPosx, newNegx float64
|
||||
k1, k2, k3, k4, k5 float64 = s.c.Property.Calc.K1, s.c.Property.Calc.K2, s.c.Property.Calc.K3, s.c.Property.Calc.K4, s.c.Property.Calc.K5
|
||||
posOffset, negOffset int64
|
||||
lawfulBase = s.c.Property.Calc.InitLawfulScore
|
||||
lawfulPosMax = s.c.Property.Calc.LawfulPosMax
|
||||
lawfulNegMax = s.c.Property.Calc.LawfulNegMax
|
||||
lawfulPosK = s.c.Property.Calc.LawfulPosK
|
||||
lawfulNegK1 = s.c.Property.Calc.LawfulNegK1
|
||||
lawfulNegK2 = s.c.Property.Calc.LawfulNegK2
|
||||
lawfulPosL = s.c.Property.Calc.LawfulPosL
|
||||
lawfulNegL = s.c.Property.Calc.LawfulNegL
|
||||
lawfulPosC3 = s.c.Property.Calc.LawfulPosC3
|
||||
lawfulNegC1 = s.c.Property.Calc.LawfulNegC1
|
||||
lawfulPosQ3 = s.c.Property.Calc.LawfulPosQ3
|
||||
lawfulNegQ1 = s.c.Property.Calc.LawfulNegQ1
|
||||
wideBase = s.c.Property.Calc.InitWideScore
|
||||
widePosMax = s.c.Property.Calc.WidePosMax
|
||||
widePosK = s.c.Property.Calc.WidePosK
|
||||
wideC1 = s.c.Property.Calc.WideC1 //有播放的活跃天数
|
||||
wideQ1 = s.c.Property.Calc.WideQ1
|
||||
wideC2 = s.c.Property.Calc.WideC2 // 账号累计经验值
|
||||
wideQ2 = s.c.Property.Calc.WideQ2
|
||||
friendlyBase = s.c.Property.Calc.InitFriendlyScore
|
||||
friendlyPosMax = s.c.Property.Calc.FriendlyPosMax
|
||||
friendlyNegMax = s.c.Property.Calc.FriendlyNegMax
|
||||
friendlyPosK = s.c.Property.Calc.FriendlyPosK
|
||||
friendlyNegK = s.c.Property.Calc.FriendlyNegK
|
||||
friendlyPosL = s.c.Property.Calc.FriendlyPosL
|
||||
friendlyNegL = s.c.Property.Calc.FriendlyNegL
|
||||
bountyBase = s.c.Property.Calc.InitBountyScore
|
||||
bountyMax = s.c.Property.Calc.BountyMax
|
||||
bountyPosL = s.c.Property.Calc.BountyPosL
|
||||
bountyK = s.c.Property.Calc.BountyK
|
||||
bountyQ1 = s.c.Property.Calc.BountyQ1
|
||||
bountyC1 = s.c.Property.Calc.BountyC1
|
||||
creativityBase = s.c.Property.Calc.InitCreativityScore
|
||||
creativityPosMax = s.c.Property.Calc.CreativityPosMax
|
||||
creativityPosK = s.c.Property.Calc.CreativityPosK
|
||||
creativityPosL1 = s.c.Property.Calc.CreativityPosL1
|
||||
)
|
||||
//1. lawful
|
||||
newPosx, posx = s.calcActionX(lawfulPosL, bizTypePosLawful, actionCounters, records, weekVer)
|
||||
posx += lawfulPosQ3 * lawfulPosC3 * float64(userInfo.DisciplineCommittee)
|
||||
posOffset = calcOffset(lawfulPosMax, lawfulPosK, posx)
|
||||
|
||||
spyScore := userInfo.SpyScore
|
||||
negx = lawfulNegQ1 * lawfulNegC1 * float64(80-float64(spyScore))
|
||||
if negx < 0 {
|
||||
negx = 0.0
|
||||
}
|
||||
negOffset = calcOffset(lawfulNegMax, lawfulNegK1, negx)
|
||||
newNegx, negx = s.calcActionX(lawfulNegL, bizTypeNegLawful, actionCounters, records, weekVer)
|
||||
negOffset += calcOffset(lawfulNegMax, lawfulNegK2, negx)
|
||||
figure.LawfulScore = int32(lawfulBase + posOffset - negOffset)
|
||||
if figure.LawfulScore < 0 {
|
||||
figure.LawfulScore = 0
|
||||
}
|
||||
newRecord.XPosLawful, newRecord.XNegLawful = int64(newPosx), int64(newNegx)
|
||||
|
||||
//2. wide
|
||||
newPosx, newNegx = 0, 0
|
||||
posx = wideQ1*wideC1*float64(userInfo.ArchiveViews) + wideQ2*wideC2*float64(userInfo.Exp)
|
||||
posOffset = calcOffset(widePosMax, widePosK, posx)
|
||||
negx = 0
|
||||
negOffset = 0
|
||||
figure.WideScore = int32(wideBase + posOffset - negOffset)
|
||||
if figure.WideScore < 0 {
|
||||
figure.WideScore = 0
|
||||
}
|
||||
newRecord.XPosWide, newRecord.XNegWide = int64(newPosx), int64(newNegx)
|
||||
|
||||
//3. friendly
|
||||
newPosx, newNegx = 0, 0
|
||||
newPosx, posx = s.calcActionX(friendlyPosL, bizTypePosFriendly, actionCounters, records, weekVer)
|
||||
posOffset = calcOffset(friendlyPosMax, friendlyPosK, posx)
|
||||
newNegx, negx = s.calcActionX(friendlyNegL, bizTypeNegFriendly, actionCounters, records, weekVer)
|
||||
negOffset = calcOffset(friendlyNegMax, friendlyNegK, negx)
|
||||
figure.FriendlyScore = int32(friendlyBase + posOffset - negOffset)
|
||||
if figure.FriendlyScore < 0 {
|
||||
figure.FriendlyScore = 0
|
||||
}
|
||||
newRecord.XPosFriendly, newRecord.XNegFriendly = int64(newPosx), int64(newNegx)
|
||||
|
||||
//4. bounty
|
||||
newPosx, newNegx = 0, 0
|
||||
var bountyVIP float64
|
||||
if userInfo.VIPStatus > 0 {
|
||||
bountyVIP = 1
|
||||
}
|
||||
newPosx, posx = s.calcActionX(bountyPosL, bizTypePosBounty, actionCounters, records, weekVer)
|
||||
posx += bountyQ1 * bountyC1 * bountyVIP
|
||||
posOffset = calcOffset(bountyMax, bountyK, posx)
|
||||
negx = 0
|
||||
negOffset = 0
|
||||
figure.BountyScore = int32(bountyBase + posOffset - negOffset)
|
||||
if figure.BountyScore < 0 {
|
||||
figure.BountyScore = 0
|
||||
}
|
||||
newRecord.XPosBounty, newRecord.XNegBounty = int64(newPosx), int64(newNegx)
|
||||
|
||||
//5. creativity
|
||||
newPosx, newNegx = 0, 0
|
||||
newPosx, posx = s.calcActionX(creativityPosL1, bizTypePosCreativity, actionCounters, records, weekVer)
|
||||
posOffset = calcOffset(creativityPosMax, creativityPosK, posx)
|
||||
negx = 0
|
||||
negOffset = 0
|
||||
figure.CreativityScore = int32(creativityBase + posOffset - negOffset)
|
||||
if figure.CreativityScore < 0 {
|
||||
figure.CreativityScore = 0
|
||||
}
|
||||
newRecord.XPosCreativity, newRecord.XNegCreativity = int64(newPosx), int64(newNegx)
|
||||
|
||||
//6. calc score
|
||||
figure.Score = int32(math.Floor(k1*float64(figure.LawfulScore) + k2*float64(figure.WideScore) + k3*float64(figure.FriendlyScore) + k4*float64(figure.CreativityScore) + k5*float64(figure.BountyScore)))
|
||||
return
|
||||
}
|
||||
|
||||
// x must >= 0
|
||||
func calcOffset(max, k, x float64) (score int64) {
|
||||
return int64(math.Floor(max * (1 - math.Pow(math.E, -(k*x)))))
|
||||
}
|
||||
|
||||
func (s *Service) calcActionX(L float64, bizType int8, actionCounters []*model.ActionCounter, records []*model.FigureRecord, weekVer int64) (newx, totalx float64) {
|
||||
var (
|
||||
day int64 = 24 * 3600
|
||||
t float64
|
||||
|
||||
lawfulPosC1 = s.c.Property.Calc.LawfulPosC1
|
||||
lawfulPosC2 = s.c.Property.Calc.LawfulPosC2
|
||||
lawfulPosQ1 = s.c.Property.Calc.LawfulPosQ1
|
||||
lawfulPosQ2 = s.c.Property.Calc.LawfulPosQ2
|
||||
lawfulNegC2 = s.c.Property.Calc.LawfulNegC2
|
||||
lawfulNegC3 = s.c.Property.Calc.LawfulNegC3
|
||||
lawfulNegQ2 = s.c.Property.Calc.LawfulNegQ2
|
||||
lawfulNegQ3 = s.c.Property.Calc.LawfulNegQ3
|
||||
|
||||
friendlyPosQ1 = s.c.Property.Calc.FriendlyPosQ1
|
||||
friendlyPosC1 = s.c.Property.Calc.FriendlyPosC1
|
||||
friendlyPosQ2 = s.c.Property.Calc.FriendlyPosQ2
|
||||
friendlyPosC2 = s.c.Property.Calc.FriendlyPosC2
|
||||
friendlyPosQ3 = s.c.Property.Calc.FriendlyPosQ3
|
||||
friendlyPosC3 = s.c.Property.Calc.FriendlyPosC3
|
||||
friendlyNegQ1 = s.c.Property.Calc.FriendlyNegQ1
|
||||
friendlyNegC1 = s.c.Property.Calc.FriendlyNegC1
|
||||
friendlyNegQ2 = s.c.Property.Calc.FriendlyNegQ2
|
||||
friendlyNegC2 = s.c.Property.Calc.FriendlyNegC2
|
||||
friendlyNegQ3 = s.c.Property.Calc.FriendlyNegQ3
|
||||
friendlyNegC3 = s.c.Property.Calc.FriendlyNegC3
|
||||
friendlyNegQ4 = s.c.Property.Calc.FriendlyNegQ4
|
||||
friendlyNegC4 = s.c.Property.Calc.FriendlyNegC4
|
||||
|
||||
creativityQ1 = s.c.Property.Calc.CreativityQ1
|
||||
creativityC1 = s.c.Property.Calc.CreativityC1
|
||||
|
||||
bountyQ2 = s.c.Property.Calc.BountyQ2
|
||||
bountyC2 = s.c.Property.Calc.BountyC2
|
||||
bountyQ3 = s.c.Property.Calc.BountyQ3
|
||||
bountyC3 = s.c.Property.Calc.BountyC3
|
||||
)
|
||||
if L == 0.0 {
|
||||
return 0, 0
|
||||
}
|
||||
for _, ac := range actionCounters {
|
||||
t = float64(7 - (ac.Version.Unix()-weekVer)/day)
|
||||
if t <= 0 {
|
||||
continue
|
||||
}
|
||||
switch bizType {
|
||||
case bizTypePosLawful:
|
||||
if ac.ReportReplyPassed < 0 {
|
||||
ac.ReportReplyPassed = 0
|
||||
}
|
||||
newx += actionX(lawfulPosQ1, lawfulPosC1, float64(ac.ReportReplyPassed), t, L)
|
||||
if ac.ReportDanmakuPassed < 0 {
|
||||
ac.ReportDanmakuPassed = 0
|
||||
}
|
||||
newx += actionX(lawfulPosQ2, lawfulPosC2, float64(ac.ReportDanmakuPassed), t, L)
|
||||
case bizTypeNegLawful:
|
||||
if ac.PublishReplyDeleted < 0 {
|
||||
ac.PublishReplyDeleted = 0
|
||||
}
|
||||
newx += actionX(lawfulNegQ2, lawfulNegC2, float64(ac.PublishReplyDeleted), t, L)
|
||||
if ac.PublishDanmakuDeleted < 0 {
|
||||
ac.PublishDanmakuDeleted = 0
|
||||
}
|
||||
newx += actionX(lawfulNegQ3, lawfulNegC3, float64(ac.PublishDanmakuDeleted), t, L)
|
||||
case bizTypePosFriendly:
|
||||
newx += actionX(friendlyPosQ1, friendlyPosC1, float64(ac.CoinCount), t, L)
|
||||
newx += actionX(friendlyPosQ2, friendlyPosC2, float64(ac.ReplyCount), t, L)
|
||||
newx += actionX(friendlyPosQ3, friendlyPosC3, float64(ac.DanmakuCount), t, L)
|
||||
case bizTypeNegFriendly:
|
||||
newx += actionX(friendlyNegQ1, friendlyNegC1, float64(ac.CoinHighRisk), t, L)
|
||||
newx += actionX(friendlyNegQ2, friendlyNegC2, float64(ac.CoinLowRisk), t, L)
|
||||
if ac.PublishReplyDeleted < 0 {
|
||||
ac.PublishReplyDeleted = 0
|
||||
}
|
||||
newx += actionX(friendlyNegQ3, friendlyNegC3, float64(ac.PublishReplyDeleted), t, L)
|
||||
if ac.PublishDanmakuDeleted < 0 {
|
||||
ac.PublishDanmakuDeleted = 0
|
||||
}
|
||||
newx += actionX(friendlyNegQ4, friendlyNegC4, float64(ac.PublishDanmakuDeleted), t, L)
|
||||
case bizTypePosCreativity:
|
||||
replyLikeCount := float64(ac.ReplyLiked) - float64(ac.ReplyUnliked)
|
||||
if replyLikeCount < 0 {
|
||||
replyLikeCount = 0.0
|
||||
}
|
||||
newx += actionX(creativityQ1, creativityC1, replyLikeCount, t, L)
|
||||
case bizTypePosBounty:
|
||||
newx += actionX(bountyQ2, bountyC2, float64(ac.PayMoney), t, L)
|
||||
newx += actionX(bountyQ3, bountyC3, float64(ac.PayLiveMoney), t, L)
|
||||
}
|
||||
}
|
||||
totalx = newx
|
||||
for _, r := range records {
|
||||
t = float64((weekVer - r.Version.Unix()) / day)
|
||||
if t <= 0 {
|
||||
continue
|
||||
}
|
||||
switch bizType {
|
||||
case bizTypePosLawful:
|
||||
totalx += actionX(1, 1, float64(r.XPosLawful), t, L)
|
||||
case bizTypeNegLawful:
|
||||
totalx += actionX(1, 1, float64(r.XNegLawful), t, L)
|
||||
case bizTypePosFriendly:
|
||||
totalx += actionX(1, 1, float64(r.XPosFriendly), t, L)
|
||||
case bizTypeNegFriendly:
|
||||
totalx += actionX(1, 1, float64(r.XNegFriendly), t, L)
|
||||
case bizTypePosCreativity:
|
||||
totalx += actionX(1, 1, float64(r.XPosCreativity), t, L)
|
||||
case bizTypePosBounty:
|
||||
totalx += actionX(1, 1, float64(r.XPosBounty), t, L)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func actionX(q, c, x, t, L float64) float64 {
|
||||
return q * c * x * math.Pow(math.E, -math.Pow((t/L), 2))
|
||||
}
|
||||
|
||||
// InitFigure initialize user figure
|
||||
func (s *Service) InitFigure(c context.Context, mid int64, ver string) (figure *model.Figure, err error) {
|
||||
figure = &model.Figure{}
|
||||
figure.Mid = mid
|
||||
figure.LawfulScore = int32(conf.Conf.Property.Calc.InitLawfulScore)
|
||||
figure.WideScore = int32(conf.Conf.Property.Calc.InitWideScore)
|
||||
figure.FriendlyScore = int32(conf.Conf.Property.Calc.InitFriendlyScore)
|
||||
figure.BountyScore = int32(conf.Conf.Property.Calc.InitBountyScore)
|
||||
figure.CreativityScore = int32(conf.Conf.Property.Calc.InitCreativityScore)
|
||||
figure.Ver = s.curVer
|
||||
|
||||
if figure.ID, err = s.dao.UpsertFigure(c, figure); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.dao.SetFigureCache(c, figure); err != nil {
|
||||
log.Error("%+v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// get ever monday start time ts.
|
||||
func weekVersion(now time.Time) (ts int64) {
|
||||
var (
|
||||
wd int
|
||||
w time.Weekday
|
||||
)
|
||||
w = now.Weekday()
|
||||
switch w {
|
||||
case time.Sunday:
|
||||
wd = 6
|
||||
default:
|
||||
wd = int(w) - 1
|
||||
}
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -wd).Unix()
|
||||
}
|
99
app/job/main/figure-timer/service/fix.go
Normal file
99
app/job/main/figure-timer/service/fix.go
Normal file
@ -0,0 +1,99 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/log"
|
||||
)
|
||||
|
||||
func (s *Service) fixproc() {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
log.Error("fixproc panic(%+v)", x)
|
||||
log.Error("%+v", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
var (
|
||||
ctx = context.TODO()
|
||||
err error
|
||||
weekVerRecordsFrom = time.Now().AddDate(0, 0, -7*52).Unix()
|
||||
weekVerRecordsTo = time.Now().Unix() + 1
|
||||
)
|
||||
for shard := s.c.Property.PendingMidStart; shard < 100; shard++ {
|
||||
log.Info("start fix: %d", shard)
|
||||
var (
|
||||
figures []*model.Figure
|
||||
fromMid = int64(shard)
|
||||
end bool
|
||||
)
|
||||
for !end {
|
||||
if figures, end, err = s.dao.Figures(ctx, fromMid, 100); err != nil {
|
||||
log.Error("%+v", err)
|
||||
break
|
||||
}
|
||||
for _, figure := range figures {
|
||||
var (
|
||||
records []*model.FigureRecord
|
||||
)
|
||||
if fromMid < figure.Mid {
|
||||
fromMid = figure.Mid
|
||||
}
|
||||
if records, err = s.dao.CalcRecords(ctx, figure.Mid, weekVerRecordsFrom, weekVerRecordsTo); err != nil {
|
||||
log.Error("%+v", err)
|
||||
continue
|
||||
}
|
||||
s.fixRecord(ctx, figure.Mid, records)
|
||||
}
|
||||
}
|
||||
log.Info("end fix: %d", shard)
|
||||
}
|
||||
}
|
||||
|
||||
// 全量清洗用户mid所有的records
|
||||
func (s *Service) fixRecord(c context.Context, mid int64, records []*model.FigureRecord) {
|
||||
var (
|
||||
err error
|
||||
action *model.ActionCounter
|
||||
x float64
|
||||
)
|
||||
for _, record := range records {
|
||||
time.Sleep(time.Millisecond)
|
||||
beforeRecord := *record
|
||||
// 获得本次record 记录对应的 action 记录
|
||||
if action, err = s.dao.ActionCounter(c, mid, record.Version.Unix()); err != nil {
|
||||
log.Error("%+v", err)
|
||||
continue
|
||||
}
|
||||
actions := []*model.ActionCounter{action}
|
||||
// lawful
|
||||
x, _ = s.calcActionX(s.c.Property.Calc.LawfulPosL, bizTypePosLawful, actions, nil, record.Version.Unix())
|
||||
record.XPosLawful = int64(x)
|
||||
x, _ = s.calcActionX(s.c.Property.Calc.LawfulNegL, bizTypeNegLawful, actions, nil, record.Version.Unix())
|
||||
record.XNegLawful = int64(x)
|
||||
// wide
|
||||
record.XPosWide = 0
|
||||
record.XNegWide = 0
|
||||
// friendly
|
||||
x, _ = s.calcActionX(s.c.Property.Calc.FriendlyPosL, bizTypePosFriendly, actions, nil, record.Version.Unix())
|
||||
record.XPosFriendly = int64(x)
|
||||
x, _ = s.calcActionX(s.c.Property.Calc.FriendlyNegL, bizTypeNegFriendly, actions, nil, record.Version.Unix())
|
||||
record.XNegFriendly = int64(x)
|
||||
// bounty
|
||||
x, _ = s.calcActionX(s.c.Property.Calc.BountyPosL, bizTypePosBounty, actions, nil, record.Version.Unix())
|
||||
record.XPosBounty = int64(x)
|
||||
record.XNegBounty = 0
|
||||
// creativity
|
||||
x, _ = s.calcActionX(s.c.Property.Calc.CreativityPosL1, bizTypePosCreativity, actions, nil, record.Version.Unix())
|
||||
record.XPosCreativity = int64(x)
|
||||
record.XNegCreativity = 0
|
||||
// 更新本次的fix
|
||||
if err = s.dao.PutCalcRecord(c, record, record.Version.Unix()); err != nil {
|
||||
log.Error("%+v", err)
|
||||
} else {
|
||||
log.Info("fix figure record before [%+v] --> now [%+v]", beforeRecord, record)
|
||||
}
|
||||
}
|
||||
}
|
83
app/job/main/figure-timer/service/rank.go
Normal file
83
app/job/main/figure-timer/service/rank.go
Normal file
@ -0,0 +1,83 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/log"
|
||||
)
|
||||
|
||||
var (
|
||||
rank = &scores{}
|
||||
)
|
||||
|
||||
type scores struct {
|
||||
ss []int32
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (s *scores) AddScore(score int32) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.ss = append(s.ss, score)
|
||||
}
|
||||
|
||||
func (s *scores) Init() {
|
||||
s.ss = make([]int32, 0)
|
||||
}
|
||||
|
||||
func (s *scores) Sort() {
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
func (s *scores) Get(i int) int32 {
|
||||
return s.ss[i]
|
||||
}
|
||||
|
||||
func (s *scores) Len() int {
|
||||
return len(s.ss)
|
||||
}
|
||||
|
||||
func (s *scores) Less(i1, i2 int) bool {
|
||||
return s.ss[i1] > s.ss[i2]
|
||||
}
|
||||
|
||||
func (s *scores) Swap(i1, i2 int) {
|
||||
s.ss[i1], s.ss[i2] = s.ss[i2], s.ss[i1]
|
||||
}
|
||||
|
||||
func (s *Service) calcRank(c context.Context, ver int64) {
|
||||
if rank.Len() <= 0 {
|
||||
return
|
||||
}
|
||||
rank.Sort()
|
||||
var (
|
||||
scoreFrom, scoreTo int32
|
||||
err error
|
||||
)
|
||||
scoreTo = rank.Get(0)
|
||||
for i := int8(1); i <= 100; i++ {
|
||||
var index int
|
||||
if i == 100 {
|
||||
scoreFrom = 0
|
||||
} else {
|
||||
index = int(float64(rank.Len()) * (float64(i) / 100.0))
|
||||
scoreFrom = rank.Get(index)
|
||||
}
|
||||
if scoreFrom > scoreTo {
|
||||
scoreTo = scoreFrom
|
||||
}
|
||||
r := &model.Rank{ScoreFrom: scoreFrom, ScoreTo: scoreTo, Percentage: i, Ver: ver}
|
||||
if _, err = s.dao.InsertRankHistory(c, r); err != nil {
|
||||
log.Error("%+v", err)
|
||||
return
|
||||
}
|
||||
if _, err = s.dao.UpsertRank(c, r); err != nil {
|
||||
log.Error("%+v", err)
|
||||
return
|
||||
}
|
||||
scoreTo = scoreFrom - 1
|
||||
}
|
||||
}
|
216
app/job/main/figure-timer/service/service.go
Normal file
216
app/job/main/figure-timer/service/service.go
Normal file
@ -0,0 +1,216 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/dao"
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/log"
|
||||
|
||||
"github.com/robfig/cron"
|
||||
)
|
||||
|
||||
// Service struct of service.
|
||||
type Service struct {
|
||||
c *conf.Config
|
||||
dao dao.Int
|
||||
missch chan func()
|
||||
curVer int64
|
||||
cron *cron.Cron
|
||||
}
|
||||
|
||||
// New create service instance and return.
|
||||
func New(c *conf.Config) (s *Service) {
|
||||
s = &Service{
|
||||
c: c,
|
||||
dao: dao.New(c),
|
||||
missch: make(chan func(), 1024),
|
||||
}
|
||||
s.cron = cron.New()
|
||||
s.cron.AddFunc(s.c.Property.CycleCron, s.cycleproc)
|
||||
if c.Property.CycleAll {
|
||||
s.cron.AddFunc(s.c.Property.CycleAllCron, s.cycleallproc)
|
||||
}
|
||||
go s.missproc()
|
||||
if c.Property.FixRecord {
|
||||
go s.fixproc()
|
||||
}
|
||||
s.cron.Start()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Service) missproc() {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
log.Error("s.missproc panic(%v)", x)
|
||||
go s.missproc()
|
||||
log.Info("s.missproc recover")
|
||||
}
|
||||
}()
|
||||
for {
|
||||
for fn := range s.missch {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) cycleproc() {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
log.Error("s.cycleproc panic(%v)", x)
|
||||
go s.cycleproc()
|
||||
log.Info("s.cycleproc recover")
|
||||
}
|
||||
}()
|
||||
var (
|
||||
err error
|
||||
mids []int64
|
||||
c = context.TODO()
|
||||
wg sync.WaitGroup
|
||||
newVer = weekVersion(time.Now().AddDate(0, 0, int(-s.c.Property.CalcWeekOffset*7)))
|
||||
)
|
||||
// Refresh Version
|
||||
atomic.StoreInt64(&s.curVer, newVer)
|
||||
log.Info("Calc active users start ver [%d]", s.curVer)
|
||||
rank.Init()
|
||||
// Calc figure concurrently
|
||||
for i := s.c.Property.PendingMidStart; i < s.c.Property.PendingMidShard; i++ {
|
||||
if mids, err = s.PendingMids(c, s.curVer, i, s.c.Property.PendingMidRetry); err != nil {
|
||||
log.Error("%+v", err)
|
||||
}
|
||||
if len(mids) == 0 {
|
||||
continue
|
||||
}
|
||||
smids := splitMids(mids, s.c.Property.ConcurrencySize)
|
||||
for c := range smids {
|
||||
csmids := smids[c]
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
wg.Done()
|
||||
}()
|
||||
for _, mid := range csmids {
|
||||
log.Info("Start handle mid [%d] figure ver [%d]", mid, s.curVer)
|
||||
if err = s.HandleFigure(context.TODO(), mid, s.curVer); err != nil {
|
||||
log.Error("%+v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
log.Info("Calc rank info start [%d]", s.curVer)
|
||||
s.calcRank(c, s.curVer)
|
||||
log.Info("Calc rank info finished [%d]", s.curVer)
|
||||
log.Info("Calc active users finished ver [%d]", s.curVer)
|
||||
}
|
||||
|
||||
func splitMids(mids []int64, concurrencySize int64) (smids [][]int64) {
|
||||
if len(mids) == 0 {
|
||||
return
|
||||
}
|
||||
if concurrencySize == 0 {
|
||||
concurrencySize = 1
|
||||
}
|
||||
step := int64(len(mids))/concurrencySize + 1
|
||||
for c := int64(0); c < concurrencySize; c++ {
|
||||
var cMids []int64
|
||||
indexFrom := c * step
|
||||
indexTo := (c + 1) * step
|
||||
if indexFrom >= int64(len(mids)) {
|
||||
break
|
||||
}
|
||||
if indexTo >= int64(len(mids)) {
|
||||
cMids = mids[indexFrom:]
|
||||
} else {
|
||||
cMids = mids[indexFrom:indexTo]
|
||||
}
|
||||
smids = append(smids, cMids)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PendingMids get pending mid list with retry
|
||||
func (s *Service) PendingMids(c context.Context, version int64, shard int64, retry int64) (mids []int64, err error) {
|
||||
var (
|
||||
maxDo = retry + 1
|
||||
doTimes int64
|
||||
)
|
||||
for doTimes < maxDo {
|
||||
if mids, err = s.dao.PendingMidsCache(c, s.curVer, shard); err != nil {
|
||||
doTimes++
|
||||
log.Info("s.dao.PendingMidsCache(%d,%d) retry (%d) error (%+v)", version, shard, doTimes, err)
|
||||
} else {
|
||||
doTimes = maxDo
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Service) cycleallproc() {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
log.Error("cycleallproc panic(%+v)", x)
|
||||
}
|
||||
}()
|
||||
var (
|
||||
ctx = context.TODO()
|
||||
err error
|
||||
newVer = weekVersion(time.Now().AddDate(0, 0, int(-s.c.Property.CalcWeekOffset*7)))
|
||||
)
|
||||
// Refresh Version
|
||||
atomic.StoreInt64(&s.curVer, newVer)
|
||||
log.Info("cycleallproc active users start ver [%d]", s.curVer)
|
||||
rank.Init()
|
||||
|
||||
for shard := s.c.Property.PendingMidStart; shard < 100; shard++ {
|
||||
log.Info("cycleallproc start run: %d", shard)
|
||||
var (
|
||||
figures []*model.Figure
|
||||
fromMid = int64(shard)
|
||||
end bool
|
||||
)
|
||||
for !end {
|
||||
if figures, end, err = s.dao.Figures(ctx, fromMid, 100); err != nil {
|
||||
log.Error("%+v", err)
|
||||
break
|
||||
}
|
||||
if len(figures) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, figure := range figures {
|
||||
if fromMid < figure.Mid {
|
||||
fromMid = figure.Mid
|
||||
}
|
||||
log.Info("Start handle mid [%d] figure ver [%d]", figure.Mid, s.curVer)
|
||||
if err = s.HandleFigure(ctx, figure.Mid, s.curVer); err != nil {
|
||||
log.Error("%+v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Info("cycleallproc rank info start [%d]", s.curVer)
|
||||
s.calcRank(ctx, s.curVer)
|
||||
log.Info("cycleallproc rank info finished [%d]", s.curVer)
|
||||
log.Info("cycleallproc active users finished ver [%d]", s.curVer)
|
||||
}
|
||||
}
|
||||
|
||||
// Close kafka consumer close.
|
||||
func (s *Service) Close() (err error) {
|
||||
s.dao.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// Wait wait service end.
|
||||
func (s *Service) Wait() {
|
||||
}
|
||||
|
||||
// Ping check service health.
|
||||
func (s *Service) Ping(c context.Context) error {
|
||||
return s.dao.Ping(c)
|
||||
}
|
177
app/job/main/figure-timer/service/service_test.go
Normal file
177
app/job/main/figure-timer/service/service_test.go
Normal file
@ -0,0 +1,177 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go-common/app/job/main/figure-timer/conf"
|
||||
"go-common/app/job/main/figure-timer/dao/mock_dao"
|
||||
"go-common/app/job/main/figure-timer/model"
|
||||
"go-common/library/log"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
var (
|
||||
s *Service
|
||||
c = context.TODO()
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
flag.Set("conf", "../cmd/figure-timer-job-test.toml")
|
||||
if err = conf.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Init(conf.Conf.Log)
|
||||
s = New(conf.Conf)
|
||||
|
||||
}
|
||||
|
||||
func TestSplitMids(t *testing.T) {
|
||||
Convey("TEST split mids", t, func() {
|
||||
var (
|
||||
mids []int64
|
||||
concurrency int64 = 100
|
||||
midsSize int64 = 233
|
||||
)
|
||||
for i := int64(0); i < midsSize; i++ {
|
||||
mids = append(mids, i)
|
||||
}
|
||||
smids := splitMids(mids, concurrency)
|
||||
actualC := concurrency
|
||||
if actualC == 0 {
|
||||
actualC = 1
|
||||
}
|
||||
if actualC > midsSize {
|
||||
actualC = midsSize
|
||||
}
|
||||
So(len(smids), ShouldEqual, 233/3+1)
|
||||
total := 0
|
||||
for s := range smids {
|
||||
total += len(smids[s])
|
||||
}
|
||||
So(total, ShouldEqual, len(mids))
|
||||
})
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
Convey("TEST week version", t, func() {
|
||||
var (
|
||||
ts = []time.Time{
|
||||
time.Date(2017, 9, 25, 0, 0, 0, 0, time.Local),
|
||||
time.Date(2017, 10, 1, 23, 59, 59, 99, time.Local),
|
||||
time.Date(2017, 9, 29, 12, 12, 12, 12, time.Local),
|
||||
}
|
||||
actual = time.Date(2017, 9, 25, 0, 0, 0, 0, time.Local)
|
||||
)
|
||||
for _, t := range ts {
|
||||
ver := weekVersion(t)
|
||||
So(ver, ShouldResemble, actual.Unix())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCalcFigure(t *testing.T) {
|
||||
Convey("TEST calc offset", t, func() {
|
||||
var (
|
||||
max = 100.0
|
||||
k = 0.1
|
||||
x1 = 10.0
|
||||
x2 = 0.0
|
||||
)
|
||||
r := calcOffset(max, k, x1)
|
||||
So(r, ShouldEqual, 63)
|
||||
r = calcOffset(max, k, x2)
|
||||
So(r, ShouldEqual, 0)
|
||||
})
|
||||
Convey("TEST calc figure", t, func() {
|
||||
var (
|
||||
userInfo = &model.UserInfo{
|
||||
Mid: 233,
|
||||
Exp: 673,
|
||||
SpyScore: 100,
|
||||
ArchiveViews: 0,
|
||||
VIPStatus: 0,
|
||||
}
|
||||
actionCounters = []*model.ActionCounter{
|
||||
{
|
||||
Mid: 233,
|
||||
CoinCount: 0,
|
||||
ReplyCount: 0,
|
||||
CoinLowRisk: 0,
|
||||
CoinHighRisk: 0,
|
||||
ReplyLowRisk: 0,
|
||||
ReplyHighRisk: 0,
|
||||
ReplyLiked: 0,
|
||||
ReplyUnliked: 0,
|
||||
Version: time.Date(2017, 10, 2, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
}
|
||||
records = []*model.FigureRecord{
|
||||
{
|
||||
XPosCreativity: 0,
|
||||
XNegFriendly: 0,
|
||||
XPosFriendly: 0,
|
||||
XNegLawful: 80,
|
||||
Version: time.Date(2017, 9, 25, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
}
|
||||
weekVer = time.Date(2018, 1, 2, 0, 0, 0, 0, time.Local).Unix()
|
||||
)
|
||||
figure, newRecord := s.CalcFigure(c, userInfo, actionCounters, records, weekVer)
|
||||
So(figure, ShouldNotBeNil)
|
||||
So(newRecord, ShouldNotBeNil)
|
||||
So(figure.LawfulScore, ShouldEqual, 2859)
|
||||
So(newRecord.XNegLawful, ShouldEqual, 0)
|
||||
So(newRecord.XPosLawful, ShouldEqual, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRank(t *testing.T) {
|
||||
rand.Seed(time.Now().Unix())
|
||||
rank.Init()
|
||||
for i := 0; i < 1; i++ {
|
||||
rank.AddScore(rand.Int31n(5000))
|
||||
}
|
||||
s.calcRank(c, time.Now().Unix())
|
||||
}
|
||||
|
||||
func TestFix(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
mockDao := mock_dao.NewMockDaoInt(ctrl)
|
||||
mockDao.EXPECT().Figures(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
[]*model.Figure{
|
||||
{Mid: 1000},
|
||||
{Mid: 2000},
|
||||
},
|
||||
true,
|
||||
nil,
|
||||
).AnyTimes()
|
||||
mockDao.EXPECT().CalcRecords(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
[]*model.FigureRecord{
|
||||
{Version: time.Date(2018, 1, 2, 0, 0, 0, 0, time.Local)},
|
||||
},
|
||||
nil,
|
||||
).AnyTimes()
|
||||
mockDao.EXPECT().ActionCounter(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&model.ActionCounter{
|
||||
PayLiveMoney: 2000,
|
||||
Version: time.Date(2018, 1, 2, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
nil,
|
||||
).AnyTimes()
|
||||
mockDao.EXPECT().PutCalcRecord(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
|
||||
s.dao = mockDao
|
||||
|
||||
Convey("TEST fix record", t, func() {
|
||||
s.fixproc()
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user