go-common/app/job/main/growup/service/income/run.go
2019-04-22 18:49:16 +08:00

539 lines
13 KiB
Go

package income
import (
"context"
"fmt"
"sort"
"time"
model "go-common/app/job/main/growup/model/income"
task "go-common/app/job/main/growup/service"
"go-common/library/log"
"golang.org/x/sync/errgroup"
)
// RunAndSendMail run and send email
func (s *Service) RunAndSendMail(c context.Context, date time.Time) (err error) {
var mailReceivers []string
var msg string
for _, v := range s.conf.Mail.Send {
if v.Type == 3 {
mailReceivers = v.Addr
}
}
startTime := time.Now().Unix()
err = s.run(c, date)
if err != nil {
msg = err.Error()
mailReceivers = []string{"shaozhenyu@bilibili.com", "gaopeng@bilibili.com", "limengqing@bilibili.com"}
} else {
msg = fmt.Sprintf("%s 计算完成,耗时%ds", date.Format("2006-01-02"), time.Now().Unix()-startTime)
}
emailErr := s.email.SendMail(date, msg, "创作激励每日计算%d年%d月%d日", mailReceivers...)
if emailErr != nil {
log.Error("s.email.SendMail error(%v)", emailErr)
}
return
}
func (s *Service) run(c context.Context, date time.Time) (err error) {
defer func() {
task.GetTaskService().SetTaskStatus(c, task.TaskCreativeIncome, date.Format(_layout), err)
}()
err = task.GetTaskService().TaskReady(c, date.Format("2006-01-02"), task.TaskAvCharge, task.TaskCmCharge, task.TaskTagRatio, task.TaskBubbleMeta, task.TaskBlacklist, task.TaskBgmSync)
if err != nil {
return
}
startWeeklyDate = getStartWeeklyDate(date)
startMonthlyDate = getStartMonthlyDate(date)
/*################ Serializable Begin ################*/
// av charge ratio
ratios, err := s.ratio.ArchiveChargeRatio(c, int64(_limitSize))
if err != nil {
return
}
// up charge ratio
urs, err := s.ratio.UpChargeRatio(c, int64(_limitSize))
if err != nil {
return
}
// av income statistics
astat, err := s.income.avIncomeStatSvr.AvIncomeStat(c, int64(_limitSize))
if err != nil {
log.Error("s.income.avIncomeStatSvr.AvIncomeStat error(%v) ", err)
return
}
log.Info("get av_income_statis : %d", len(astat))
// bgm income statistics
bstat, err := s.income.bgmIncomeStatSvr.BgmIncomeStat(c, int64(_limitSize))
if err != nil {
log.Error("s.income.bgmIncomeStatSvr.BgmIncomeStat error(%v) ", err)
return
}
log.Info("get bgm_income_statis : %d", len(bstat))
// column income statistics
cstat, err := s.income.columnIncomeStatSvr.ColumnIncomeStat(c, int64(_limitSize))
if err != nil {
log.Error("s.income.columnIncomeStatSvr.ColumnIncomeStat error(%v) ", err)
return
}
log.Info("get column_income_statis : %d", len(cstat))
// up income statistics
ustat, err := s.income.upIncomeStatSvr.UpIncomeStat(c, int64(_limitSize))
if err != nil {
log.Error("s.income.upIncomeStatSvr.UpIncomeStat error(%v) ", err)
return
}
log.Info("get up_income_statis : %d", len(ustat))
// up accounts
accs, err := s.income.upAccountSvr.UpAccount(c, int64(_limitSize))
if err != nil {
log.Error("s.income.upAccountSvr.UpAccount error(%v)", err)
return
}
log.Info("get up_account : %d", len(accs))
// bubble meta
bubbleMeta, err := s.GetBubbleMeta(c)
if err != nil {
log.Error("s.GetBubbleMeta error(%v)", err)
return
}
log.Info("get lottery_av_info avids: %d", len(bubbleMeta))
bubbleRatio := s.avToBubbleRatio(bubbleMeta)
// av signed ups
var (
avFilters []AvFilter
columnFilters []ColumnFilter
bgmFilter BgmFilter
)
//black list
blacks, err := s.Blacklist(c, 2000)
if err != nil {
return
}
// black ctype 0: av
avBlackFilter := avFilter(blacks[0])
// black ctype 2: column
columnBlackFilter := columnFilter(blacks[2])
// business orders
bos, err := s.GetBusinessOrders(c, 2000)
if err != nil {
return
}
bosFilter := avFilter(bos)
// signed up
signed := make(map[int64]bool)
signedAv, err := s.Signed(c, "video", 2000)
if err != nil {
return
}
savf := signedAvFilter(signedAv, date)
for mid := range signedAv {
signed[mid] = true
}
signedColumn, err := s.Signed(c, "column", 2000)
if err != nil {
return
}
for mid := range signedColumn {
signed[mid] = true
}
signedBgm, err := s.Signed(c, "bgm", 2000)
if err != nil {
return
}
for mid := range signedBgm {
signed[mid] = true
}
bgms, err := s.BGMs(c, 2000)
if err != nil {
return
}
{
avFilters = append(avFilters, avBlackFilter)
avFilters = append(avFilters, bosFilter)
avFilters = append(avFilters, savf)
bgmFilter = signedBgmFilter(signedBgm, date)
columnFilters = append(columnFilters, signedColumnFilter(signedColumn, date))
columnFilters = append(columnFilters, columnBlackFilter)
}
/*################ Serializable End ##################*/
var (
readGroup errgroup.Group
sourceCh = make(chan []*model.AvCharge, 1000)
// av
incomeCh = make(chan []*model.AvCharge, 1000)
// bgm
bgmCh = make(chan []*model.AvCharge, 1000)
// column
columnSourceCh = make(chan []*model.ColumnCharge, 1000)
// business income
businessCh = make(chan map[int64]*model.UpBusinessIncome, 10)
)
// get av daily charge and repost to other channels
readGroup.Go(func() (err error) {
err = s.avCharge.AvCharges(c, date, sourceCh, bubbleRatio)
if err != nil {
log.Error("s.avCharge.AvCharges error(%v)", err)
return
}
log.Info("av_daily_charge finished")
return
})
// get column daily charge
readGroup.Go(func() (err error) {
err = s.columnCharges(c, date, columnSourceCh)
if err != nil {
log.Error("s.columnCharges error(%v)", err)
return
}
log.Info("column_daily_charge finished")
return
})
readGroup.Go(func() (err error) {
defer func() {
close(incomeCh)
close(bgmCh)
}()
for charges := range sourceCh {
incomeCh <- charges
bgmCh <- charges
}
return
})
// up and av income compute
var (
um map[int64]*model.UpIncome
am map[int64][]*model.AvIncome
bm map[int64]map[int64]map[int64]*model.BgmIncome
cm map[int64][]*model.ColumnIncome
)
readGroup.Go(func() (err error) {
//um, am = s.income.Compute(c, date, incomeCh, urs, ars, ustat, astat, accs, filters, signed)
var business map[int64]*model.UpBusinessIncome
am, business = s.income.CalAvIncome(incomeCh, urs[1], ratios[1], avFilters, signed)
businessCh <- business
return
})
readGroup.Go(func() (err error) {
var business map[int64]*model.UpBusinessIncome
bm, business = s.income.CalBgmIncome(bgmCh, bgms, urs[3], ratios[3], avFilters, bgmFilter, blacks[3], signed)
businessCh <- business
return
})
readGroup.Go(func() (err error) {
var business map[int64]*model.UpBusinessIncome
cm, business = s.income.CalColumnIncome(columnSourceCh, urs[2], ratios[2], columnFilters, signed)
businessCh <- business
return
})
readGroup.Go(func() (err error) {
um = s.income.CalUpIncome(businessCh, date)
s.income.IncomeStat(um, am, bm, cm, ustat, astat, bstat, cstat)
s.income.PurgeUpAccount(date, accs, um)
return
})
if err = readGroup.Wait(); err != nil {
log.Error("run readGroup.Wait error(%v)", err)
return
}
// security verification
{
if len(am) == 0 {
err = fmt.Errorf("Error: insert 0 av_income")
return
}
if len(bm) == 0 {
err = fmt.Errorf("Error: insert 0 bgm_income")
return
}
if len(cm) == 0 {
err = fmt.Errorf("Error: insert 0 column_income")
return
}
if len(um) == 0 {
err = fmt.Errorf("Error: insert 0 up_income")
return
}
if len(astat) == 0 {
err = fmt.Errorf("Error: insert 0 av_income_statis")
return
}
if len(bstat) == 0 {
err = fmt.Errorf("Error: insert 0 bgm_income_statis")
return
}
if len(cstat) == 0 {
err = fmt.Errorf("Error: insert 0 column_income_statis")
return
}
if len(ustat) == 0 {
err = fmt.Errorf("Error: insert 0 up_income_statis")
return
}
if len(accs) == 0 {
err = fmt.Errorf("Error: insert 0 up_account")
return
}
}
// persistent
var writeGroup errgroup.Group
// av_income
writeGroup.Go(func() (err error) {
err = s.income.avIncomeSvr.BatchInsertAvIncome(c, am)
if err != nil {
log.Error("s.income.BatchInsertAvIncome error(%v)", err)
return
}
log.Info("insert av_income : %d", len(am))
return
})
// column_income
writeGroup.Go(func() (err error) {
err = s.income.columnIncomeSvr.BatchInsertColumnIncome(c, cm)
if err != nil {
log.Error("s.income.BatchInsertColumnIncome error(%v)", err)
return
}
log.Info("insert column_income : %d", len(cm))
return
})
// bgm_income
writeGroup.Go(func() (err error) {
err = s.income.bgmIncomeSvr.BatchInsertBgmIncome(c, bm)
if err != nil {
log.Error("s.income.BatchInsertBgmIncome error(%v)", err)
return
}
log.Info("insert bgm_income : %d", len(bm))
return
})
// up income
writeGroup.Go(func() (err error) {
err = s.income.upIncomeSvr.BatchInsertUpIncome(c, um)
if err != nil {
log.Error("s.income.BatchInsertUpIncome error(%v)", err)
return
}
log.Info("insert up_income : %d", len(um))
return
})
// av_income_statis
writeGroup.Go(func() (err error) {
err = s.income.avIncomeStatSvr.BatchInsertAvIncomeStat(c, astat)
if err != nil {
log.Error("s.income.BatchInsertAvIncomeStat error(%v)", err)
return
}
log.Info("insert av_income_statis : %d", len(astat))
return
})
// column_income_statis
writeGroup.Go(func() (err error) {
err = s.income.columnIncomeStatSvr.BatchInsertColumnIncomeStat(c, cstat)
if err != nil {
log.Error("s.income.BatchInsertColumnIncomeStat error(%v)", err)
return
}
log.Info("insert column_income_statis : %d", len(cstat))
return
})
// bgm_income_statis
writeGroup.Go(func() (err error) {
err = s.income.bgmIncomeStatSvr.BatchInsertBgmIncomeStat(c, bstat)
if err != nil {
log.Error("s.income.BatchInsertBgmIncomeStat error(%v)", err)
return
}
log.Info("insert bgm_income_statis : %d", len(bstat))
return
})
// up_income_statis
writeGroup.Go(func() (err error) {
err = s.income.upIncomeStatSvr.BatchInsertUpIncomeStat(c, ustat)
if err != nil {
log.Error("s.income.BatchInsertUpIncomeStat error(%v)", err)
return
}
log.Info("insert up_income_statis : %d", len(ustat))
return
})
// up_account batch insert
writeGroup.Go(func() (err error) {
err = s.income.upAccountSvr.BatchInsertUpAccount(c, accs)
if err != nil {
log.Error("s.income.BatchInsertUpAccount error(%v)", err)
return
}
log.Info("insert up_account : %d", len(accs))
return
})
// up account single update
writeGroup.Go(func() (err error) {
err = s.income.upAccountSvr.UpdateUpAccount(c, accs)
if err != nil {
log.Error("s.income.UpdateUpAccount error(%v)", err)
return
}
log.Info("update up_account : %d", len(accs))
return
})
if err = writeGroup.Wait(); err != nil {
log.Error("run writeGroup.Wait error(%v)", err)
}
return
}
func signedBgmFilter(m map[int64]*model.Signed, date time.Time) BgmFilter {
return func(charge *model.AvCharge, bgm *model.BGM) bool {
if up, ok := m[bgm.MID]; ok {
if charge.Date.Time().Before(up.SignedAt.Time()) {
return true
}
if (up.AccountState == 5 || up.AccountState == 6) && up.QuitAt.Time().Before(date.AddDate(0, 0, 1)) {
return true
}
} else {
return true
}
return false
}
}
func signedAvFilter(m map[int64]*model.Signed, date time.Time) AvFilter {
return func(charge *model.AvCharge) bool {
if up, ok := m[charge.MID]; ok {
if charge.UploadTime.Time().Before(up.SignedAt.Time()) {
return true
}
if (up.AccountState == 5 || up.AccountState == 6) && up.QuitAt.Time().Before(date.AddDate(0, 0, 1)) {
return true
}
} else {
return true
}
return false
}
}
func signedColumnFilter(m map[int64]*model.Signed, date time.Time) ColumnFilter {
return func(charge *model.ColumnCharge) bool {
if up, ok := m[charge.MID]; ok {
if charge.UploadTime.Time().Before(up.SignedAt.Time()) {
return true
}
if (up.AccountState == 5 || up.AccountState == 6) && up.QuitAt.Time().Before(date.AddDate(0, 0, 1)) {
return true
}
} else {
return true
}
return false
}
}
func avFilter(m map[int64]bool) AvFilter {
return func(charge *model.AvCharge) bool {
return m[charge.AvID]
}
}
func columnFilter(m map[int64]bool) ColumnFilter {
return func(charge *model.ColumnCharge) bool {
return m[charge.ArticleID]
}
}
func (s *Service) avToBubbleRatio(bubbleMeta map[int64][]int) map[int64]float64 {
var (
res = make(map[int64]float64)
typeToRatio = make(map[int]float64)
chooseBType = func(bTypes []int) (bType int) {
if len(bTypes) == 1 {
return bTypes[0]
}
sort.Slice(bTypes, func(i, j int) bool {
bti, btj := bTypes[i], bTypes[j]
if typeToRatio[bti] == typeToRatio[btj] {
return bti < btj
}
return typeToRatio[bti] < typeToRatio[btj]
})
return bTypes[0]
}
)
for _, v := range s.conf.Bubble.BRatio {
typeToRatio[v.BType] = v.Ratio
}
for avID, bTypes := range bubbleMeta {
bType := chooseBType(bTypes)
res[avID] = typeToRatio[bType]
}
return res
}
// BgmFilter av charge filter
type BgmFilter func(*model.AvCharge, *model.BGM) bool
// AvFilter av charge filter
type AvFilter func(*model.AvCharge) bool
// ColumnFilter column charge filter
type ColumnFilter func(*model.ColumnCharge) bool
// ChargeRegulator regulates av charge
type ChargeRegulator func(*model.AvCharge)
// UpdateBusinessIncome ..
func (s *Service) UpdateBusinessIncome(c context.Context, date string) (err error) {
return s.income.UpdateBusinessIncomeByDate(c, date)
}