129 lines
2.7 KiB
Go
129 lines
2.7 KiB
Go
|
package abtest
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"time"
|
||
|
|
||
|
"go-common/app/interface/main/app-resource/conf"
|
||
|
expdao "go-common/app/interface/main/app-resource/dao/abtest"
|
||
|
"go-common/app/interface/main/app-resource/model/experiment"
|
||
|
"go-common/app/service/main/resource/model"
|
||
|
"go-common/library/log"
|
||
|
|
||
|
farm "github.com/dgryski/go-farm"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
_emptyExperiment = []*experiment.Experiment{}
|
||
|
_defaultExperiment = map[int8][]*experiment.Experiment{
|
||
|
model.PlatAndroid: []*experiment.Experiment{
|
||
|
&experiment.Experiment{
|
||
|
ID: 10,
|
||
|
Name: "默认值",
|
||
|
Strategy: "default_value",
|
||
|
Desc: "默认值为不匹配处理",
|
||
|
TrafficGroup: "0",
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
)
|
||
|
|
||
|
type Service struct {
|
||
|
dao *expdao.Dao
|
||
|
// tick
|
||
|
tick time.Duration
|
||
|
epm map[int8][]*experiment.Experiment
|
||
|
c *conf.Config
|
||
|
}
|
||
|
|
||
|
func New(c *conf.Config) (s *Service) {
|
||
|
s = &Service{
|
||
|
c: c,
|
||
|
dao: expdao.New(c),
|
||
|
// tick
|
||
|
tick: time.Duration(c.Tick),
|
||
|
epm: map[int8][]*experiment.Experiment{},
|
||
|
}
|
||
|
s.loadAbTest()
|
||
|
go s.tickproc()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// TemporaryABTests 临时的各种abtest垃圾需求
|
||
|
func (s *Service) TemporaryABTests(c context.Context, buvid string) (tests *experiment.ABTestV2) {
|
||
|
id := farm.Hash32([]byte(buvid))
|
||
|
n := int(id % 100)
|
||
|
autoPlay := 1
|
||
|
if n > s.c.ABTest.Range {
|
||
|
autoPlay = 2
|
||
|
}
|
||
|
tests = &experiment.ABTestV2{
|
||
|
AutoPlay: autoPlay,
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (s *Service) Experiment(c context.Context, plat int8, build int) (eps []*experiment.Experiment) {
|
||
|
if es, ok := s.epm[plat]; ok {
|
||
|
LOOP:
|
||
|
for _, ep := range es {
|
||
|
for _, l := range ep.Limit {
|
||
|
if model.InvalidBuild(build, l.Build, l.Condition) {
|
||
|
continue LOOP
|
||
|
}
|
||
|
}
|
||
|
eps = append(eps, ep)
|
||
|
}
|
||
|
}
|
||
|
if eps == nil {
|
||
|
if es, ok := _defaultExperiment[plat]; ok {
|
||
|
eps = es
|
||
|
} else {
|
||
|
eps = _emptyExperiment
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// tickproc tick load cache.
|
||
|
func (s *Service) tickproc() {
|
||
|
for {
|
||
|
time.Sleep(s.tick)
|
||
|
s.loadAbTest()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *Service) loadAbTest() {
|
||
|
c := context.TODO()
|
||
|
lm, err := s.dao.ExperimentLimit(c)
|
||
|
if err != nil {
|
||
|
log.Error("s.dao.ExperimentLimit error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
ids := make([]int64, 0, len(lm))
|
||
|
for id := range lm {
|
||
|
ids = append(ids, id)
|
||
|
}
|
||
|
if len(ids) == 0 {
|
||
|
return
|
||
|
}
|
||
|
eps, err := s.dao.ExperimentByIDs(c, ids)
|
||
|
if err != nil {
|
||
|
log.Error("s.dao.ExperimentByIDs(%v) error(%v)", ids, err)
|
||
|
return
|
||
|
}
|
||
|
epm := make(map[int8][]*experiment.Experiment, len(eps))
|
||
|
for _, ep := range eps {
|
||
|
if l, ok := lm[ep.ID]; ok {
|
||
|
ep.Limit = l
|
||
|
}
|
||
|
epm[ep.Plat] = append(epm[ep.Plat], ep)
|
||
|
}
|
||
|
s.epm = epm
|
||
|
}
|
||
|
|
||
|
// AbServer is
|
||
|
func (s *Service) AbServer(c context.Context, buvid, device, mobiAPP, filteredStr string, build int, mid int64) (a interface{}, err error) {
|
||
|
return s.dao.AbServer(c, buvid, device, mobiAPP, filteredStr, build, mid)
|
||
|
}
|