Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
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/sms/conf:go_default_library",
"//app/job/main/sms/model:go_default_library",
"//app/service/main/sms/model:go_default_library",
"//library/net/trace:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"callback.go",
"log.go",
"service.go",
"sms.go",
],
importpath = "go-common/app/job/main/sms/service",
tags = ["automanaged"],
deps = [
"//app/job/main/sms/conf:go_default_library",
"//app/job/main/sms/dao:go_default_library",
"//app/job/main/sms/dao/chuanglan:go_default_library",
"//app/job/main/sms/dao/mengwang:go_default_library",
"//app/job/main/sms/model:go_default_library",
"//app/service/main/sms/api:go_default_library",
"//app/service/main/sms/model:go_default_library",
"//library/conf/env:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,160 @@
package service
import (
"context"
"strconv"
"time"
"go-common/app/job/main/sms/dao/chuanglan"
"go-common/app/job/main/sms/dao/mengwang"
smsmdl "go-common/app/service/main/sms/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const (
_callbackSize = 100
)
func (s *Service) dispatchCallback(provider int32) {
switch provider {
case smsmdl.ProviderChuangLan:
s.waiter.Add(1)
go s.callbackChuangLanproc()
case smsmdl.ProviderMengWang:
s.waiter.Add(1)
go s.callbackMengWangproc()
}
}
func (s *Service) callbackChuangLanproc() {
defer s.waiter.Done()
log.Info("callbackChuangLanproc start")
group := errgroup.Group{}
cli := chuanglan.NewClient(s.c)
for {
if s.closed {
log.Info("callbackChuangLanproc exit")
return
}
group.Go(func() error {
callbacks, err := cli.Callback(context.Background(), s.c.Provider.ChuangLanSmsUser, s.c.Provider.ChuangLanSmsPwd, s.c.Provider.ChuangLanSmsCallbackURL, _callbackSize)
if err != nil {
time.Sleep(time.Second)
return nil
}
s.sendChuangLanCallbacks(smsmdl.TypeSms, callbacks)
return nil
})
group.Go(func() error {
callbacks, err := cli.Callback(context.Background(), s.c.Provider.ChuangLanActUser, s.c.Provider.ChuangLanActPwd, s.c.Provider.ChuangLanActCallbackURL, _callbackSize)
if err != nil {
time.Sleep(time.Second)
return nil
}
s.sendChuangLanCallbacks(smsmdl.TypeActSms, callbacks)
return nil
})
group.Go(func() error {
callbacks, err := cli.CallbackInternational(context.Background(), _callbackSize)
if err != nil {
time.Sleep(time.Second)
return nil
}
s.sendChuangLanCallbacks(smsmdl.TypeSms, callbacks)
return nil
})
group.Wait()
time.Sleep(time.Second)
}
}
func (s *Service) sendChuangLanCallbacks(typ int32, cbs []*chuanglan.Callback) (err error) {
ts := time.Now().Unix()
for _, cb := range cbs {
if cb.NotifyTime != "" {
if t, e := time.ParseInLocation("060102150405", cb.NotifyTime, time.Local); e != nil {
log.Warn("sendChuangLanCallbacks(%+v) parse time error(%v)", cb, e)
} else {
ts = t.Unix()
}
}
s.sendUserActionLog(&smsmdl.ModelUserActionLog{
MsgID: cb.MsgID,
Mobile: cb.Mobile,
Status: cb.Status,
Desc: cb.Desc,
Provider: smsmdl.ProviderChuangLan,
Type: typ,
Action: smsmdl.UserActionCallback,
Ts: ts,
})
}
return
}
func (s *Service) callbackMengWangproc() {
defer s.waiter.Done()
log.Info("callbackMengWangproc start")
group := errgroup.Group{}
cli := mengwang.NewClient(s.c)
for {
if s.closed {
log.Info("callbackMengWangproc exit")
return
}
group.Go(func() error {
callbacks, err := cli.Callback(context.Background(), s.c.Provider.MengWangSmsUser, s.c.Provider.MengWangSmsPwd, s.c.Provider.MengWangSmsCallbackURL, _callbackSize)
if err != nil {
time.Sleep(time.Second)
return nil
}
s.sendMengWangCallbacks(smsmdl.TypeSms, callbacks)
return nil
})
group.Go(func() error {
callbacks, err := cli.Callback(context.Background(), s.c.Provider.MengWangActUser, s.c.Provider.MengWangActPwd, s.c.Provider.MengWangActCallbackURL, _callbackSize)
if err != nil {
time.Sleep(time.Second)
return nil
}
s.sendMengWangCallbacks(smsmdl.TypeActSms, callbacks)
return nil
})
group.Go(func() error {
callbacks, err := cli.Callback(context.Background(), s.c.Provider.MengWangInternationUser, s.c.Provider.MengWangInternationPwd, s.c.Provider.MengWangInternationalCallbackURL, _callbackSize)
if err != nil {
time.Sleep(time.Second)
return nil
}
s.sendMengWangCallbacks(smsmdl.TypeSms, callbacks)
return nil
})
group.Wait()
time.Sleep(time.Second)
}
}
func (s *Service) sendMengWangCallbacks(typ int32, cbs []*mengwang.Callback) (err error) {
ts := time.Now().Unix()
for _, cb := range cbs {
if cb.ReportTime != "" {
if t, e := time.ParseInLocation("2006-01-02 15:04:05", cb.ReportTime, time.Local); e != nil {
log.Warn("sendMengWangCallbacks(%+v) parse time error(%v)", cb, e)
} else {
ts = t.Unix()
}
}
s.sendUserActionLog(&smsmdl.ModelUserActionLog{
MsgID: strconv.FormatInt(cb.MsgID, 10),
Mobile: cb.Mobile,
Status: cb.Status,
Desc: cb.Desc,
Provider: smsmdl.ProviderMengWang,
Type: typ,
Action: smsmdl.UserActionCallback,
Ts: ts,
})
}
return
}

View File

@@ -0,0 +1,39 @@
package service
import (
"strings"
"time"
smsmdl "go-common/app/service/main/sms/model"
"go-common/library/log"
"go-common/library/queue/databus/report"
)
const (
_reportType = 111
)
func (s *Service) sendUserActionLog(l *smsmdl.ModelUserActionLog) {
if l.Mobile == "" {
log.Warn("sendUserActionLog mobile is empty, log(%+v)", l)
return
}
for _, mobile := range strings.Split(l.Mobile, ",") {
r := &report.UserInfo{
Business: _reportType,
Ctime: time.Unix(l.Ts, 0),
Index: []interface{}{mobile},
Content: map[string]interface{}{
"msgid": l.MsgID,
"content": l.Content,
"status": l.Status,
"desc": l.Desc,
"provider": l.Provider,
"type": l.Type,
"action": l.Action,
},
}
log.Info("sendUserActionLog(%+v)", r)
report.User(r)
}
}

View File

@@ -0,0 +1,150 @@
package service
import (
"context"
"sync"
"go-common/app/job/main/sms/conf"
"go-common/app/job/main/sms/dao"
"go-common/app/job/main/sms/dao/chuanglan"
"go-common/app/job/main/sms/dao/mengwang"
"go-common/app/job/main/sms/model"
smsgrpc "go-common/app/service/main/sms/api"
smsmdl "go-common/app/service/main/sms/model"
"go-common/library/log"
"go-common/library/queue/databus"
"go-common/library/sync/pipeline/fanout"
)
// Service struct of service.
type Service struct {
c *conf.Config
dao *dao.Dao
databus *databus.Databus
smsgrpc smsgrpc.SmsClient
waiter *sync.WaitGroup
sms chan *smsmdl.ModelSend // 验证码
actSms chan *smsmdl.ModelSend // 营销
batchSms chan *smsmdl.ModelSend // 批量
smsp *model.ConcurrentRing
intep *model.ConcurrentRing
actp *model.ConcurrentRing
batchp *model.ConcurrentRing
cache *fanout.Fanout
providers int
closed bool
smsCount int64
blacklist map[string]struct{}
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
proLen := len(c.Provider.Providers)
if c.Speedup.Switch {
proLen *= 2 // 每个短信服务商再提供一个云线路 http client
}
s = &Service{
c: c,
dao: dao.New(c),
databus: databus.New(c.Databus),
waiter: new(sync.WaitGroup),
sms: make(chan *smsmdl.ModelSend, 10240),
actSms: make(chan *smsmdl.ModelSend, 10240),
batchSms: make(chan *smsmdl.ModelSend, 10240),
smsp: model.NewConcurrentRing(proLen),
intep: model.NewConcurrentRing(proLen),
actp: model.NewConcurrentRing(proLen),
batchp: model.NewConcurrentRing(proLen),
cache: fanout.New("async-task", fanout.Worker(1), fanout.Buffer(10240)),
providers: proLen,
}
s.initBlacklist()
var err error
if s.smsgrpc, err = smsgrpc.NewClient(c.SmsGRPC); err != nil {
panic(err)
}
s.initProviders()
s.waiter.Add(1)
go s.subproc()
go s.monitorproc()
for i := 0; i < s.c.Sms.SingleSendProc; i++ {
s.waiter.Add(1)
go s.smsproc()
s.waiter.Add(1)
go s.actsmsproc()
}
for i := 0; i < s.c.Sms.BatchSendProc; i++ {
s.waiter.Add(1)
go s.actbatchproc()
}
return
}
func (s *Service) initBlacklist() {
s.blacklist = make(map[string]struct{})
for _, v := range s.c.Sms.Blacklist {
s.blacklist[v] = struct{}{}
}
}
func (s *Service) initProviders() {
// 创建本地网络 http client
s.newProviders(s.c)
if !s.c.Speedup.Switch {
return
}
// 替换成 云加速线路 URL 配置
s.c.Provider.MengWangSmsURL = s.c.Speedup.MengWangSmsURL
s.c.Provider.MengWangActURL = s.c.Speedup.MengWangActURL
s.c.Provider.MengWangBatchURL = s.c.Speedup.MengWangBatchURL
s.c.Provider.MengWangInternationURL = s.c.Speedup.MengWangInternationURL
s.c.Provider.ChuangLanSmsURL = s.c.Speedup.ChuangLanSmsURL
s.c.Provider.ChuangLanActURL = s.c.Speedup.ChuangLanActURL
s.c.Provider.ChuangLanInternationURL = s.c.Speedup.ChuangLanInternationURL
s.c.Provider.MengWangSmsCallbackURL = s.c.Speedup.MengWangSmsCallbackURL
s.c.Provider.MengWangActCallbackURL = s.c.Speedup.MengWangActCallbackURL
s.c.Provider.MengWangInternationalCallbackURL = s.c.Speedup.MengWangInternationalCallbackURL
s.c.Provider.ChuangLanSmsCallbackURL = s.c.Speedup.ChuangLanSmsCallbackURL
s.c.Provider.ChuangLanActCallbackURL = s.c.Speedup.ChuangLanActCallbackURL
s.c.Provider.ChuangLanInternationalCallbackURL = s.c.Speedup.ChuangLanInternationalCallbackURL
// 创建云加速线路 http client
s.newProviders(s.c)
}
func (s *Service) newProviders(c *conf.Config) {
var cli model.Provider
for _, p := range c.Provider.Providers {
switch p {
case smsmdl.ProviderMengWang:
cli = mengwang.NewClient(c)
case smsmdl.ProviderChuangLan:
cli = chuanglan.NewClient(c)
default:
log.Error("invalid provider(%d)", p)
continue
}
s.smsp.Value = cli
s.smsp.Ring = s.smsp.Next()
s.intep.Value = cli
s.intep.Ring = s.intep.Next()
s.actp.Value = cli
s.actp.Ring = s.actp.Next()
s.batchp.Value = cli
s.batchp.Ring = s.batchp.Next()
for i := 0; i < s.c.Sms.CallbackProc; i++ {
s.dispatchCallback(p)
}
}
}
// Ping check service health.
func (s *Service) Ping(ctx context.Context) error {
return s.dao.Ping(ctx)
}
// Close kafka consumer close.
func (s *Service) Close() {
s.closed = true
s.databus.Close()
s.waiter.Wait()
}

View File

@@ -0,0 +1,74 @@
package service
import (
"container/ring"
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/job/main/sms/conf"
"go-common/app/job/main/sms/model"
smsmdl "go-common/app/service/main/sms/model"
"go-common/library/net/trace"
. "github.com/smartystreets/goconvey/convey"
)
var srv *Service
func init() {
dir, _ := filepath.Abs("../cmd/sms-job-test.toml")
flag.Set("conf", dir)
conf.Init()
srv = New(conf.Conf)
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
f(srv)
}
}
func Test_ring(t *testing.T) {
Convey("test ring", t, WithService(func(s *Service) {
r := ring.New(3)
r.Value = 0
r = r.Next()
r.Value = 1
r = r.Next()
r.Value = 2
So(r.Len(), ShouldEqual, 3)
for i := 0; i < 5; i++ {
r = r.Next()
t.Logf("%d", r.Value)
}
}))
}
func Test_Sms(t *testing.T) {
Convey("sms", t, WithService(func(s *Service) {
// http request会自动加trace header不init trace的话,header value为空为会兴企reset
trace.Init(s.c.Tracer)
defer trace.Close()
c := context.TODO()
sl := &smsmdl.ModelSend{Mobile: "", Content: "您的账号正在哔哩哔哩2017动画角色人气大赏活动中进行领票操作验证码为123456当日有效", Code: "whatever", Type: 1}
p := s.smsp.Value.(model.Provider)
_, err := p.SendSms(c, sl)
So(err, ShouldBeNil)
s.smsp.Ring = s.smsp.Next()
p = s.smsp.Value.(model.Provider)
_, err = p.SendSms(c, sl)
So(err, ShouldBeNil)
s.smsp.Ring = s.smsp.Next()
p = s.smsp.Value.(model.Provider)
_, err = p.SendSms(c, sl)
So(err, ShouldBeNil)
s.smsp.Ring = s.smsp.Next()
p = s.smsp.Value.(model.Provider)
_, err = p.SendSms(c, sl)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,311 @@
package service
import (
"context"
"encoding/json"
"fmt"
"regexp"
"strconv"
"strings"
"time"
"go-common/app/job/main/sms/dao"
"go-common/app/job/main/sms/model"
smsmdl "go-common/app/service/main/sms/model"
"go-common/library/conf/env"
"go-common/library/log"
)
const _retry = 3
var _contentRe = regexp.MustCompile(`\d`)
func (s *Service) subproc() {
defer s.waiter.Done()
for {
item, ok := <-s.databus.Messages()
if !ok {
close(s.sms)
close(s.actSms)
close(s.batchSms)
log.Info("databus: sms-job subproc consumer exit!")
return
}
s.smsCount++
msg := new(smsmdl.ModelSend)
if err := json.Unmarshal(item.Value, &msg); err != nil {
log.Error("json.Unmarshal (%v) error(%v)", string(item.Value), err)
continue
}
log.Info("subproc topic(%s) key(%s) partition(%v) offset(%d) message(%s)", item.Topic, item.Key, item.Partition, item.Offset, item.Value)
// 黑名单,用于压测
if _, ok := s.blacklist[msg.Country+msg.Mobile]; ok {
log.Info("country(%s) mobile(%s) in blacklist", msg.Country, msg.Mobile)
item.Commit()
continue
}
switch msg.Type {
case smsmdl.TypeSms:
s.sms <- msg
case smsmdl.TypeActSms:
s.actSms <- msg
case smsmdl.TypeActBatch:
s.batchSms <- msg
}
item.Commit()
}
}
func (s *Service) smsproc() {
defer s.waiter.Done()
var (
err error
msgid string
)
for {
m, ok := <-s.sms
if !ok {
log.Info("smsproc exit!")
return
}
if m.Mobile == "" {
if m.Country, m.Mobile, err = s.userMobile(m.Mid); err != nil {
continue
}
}
if m.Country == "" || m.Mobile == "" {
log.Error("invalid country or mobile, info(%+v)", m)
continue
}
content := _contentRe.ReplaceAllString(m.Content, "*")
l := &smsmdl.ModelUserActionLog{Mobile: m.Mobile, Content: content, Type: smsmdl.TypeSms, Action: smsmdl.UserActionTypeSend}
if m.Country == smsmdl.CountryChina {
for i := 0; i < s.providers; i++ {
s.smsp.Lock()
p := s.smsp.Value.(model.Provider)
s.smsp.Ring = s.smsp.Next()
s.smsp.Unlock()
l.Provider = p.GetPid()
if msgid, err = p.SendSms(context.Background(), m); err == nil {
break
}
dao.PromInfo(fmt.Sprintf("service:retry %d", l.Provider))
log.Error("retry send sms(%v) platform(%d) error(%v)", m, l.Provider, err)
}
} else {
for i := 0; i < s.providers; i++ {
s.intep.Lock()
p := s.intep.Value.(model.Provider)
s.intep.Ring = s.intep.Next()
s.intep.Unlock()
l.Provider = p.GetPid()
if msgid, err = p.SendInternationalSms(context.Background(), m); err == nil {
break
}
dao.PromInfo(fmt.Sprintf("service:retry international %d", l.Provider))
log.Error("retry send international sms(%v) platform(%d) error(%v)", m, l.Provider, err)
}
}
if err == nil {
l.Status = smsmdl.UserActionSendSuccessStatus
l.Desc = smsmdl.UserActionSendSuccessDesc
dao.PromInfo(fmt.Sprintf("service:success %d", l.Provider))
log.Info("send sms(%v) platform(%d) success", m, l.Provider)
} else {
l.Status = smsmdl.UserActionSendFailedStatus
l.Desc = smsmdl.UserActionSendFailedDesc
dao.PromError("service:sms")
log.Error("send sms(%v) error(%v)", m, err)
s.cache.Do(context.Background(), func(ctx context.Context) {
s.dao.SendWechat(fmt.Sprintf("sms-job send msg(%d) error(%v)", m.ID, err))
})
}
l.MsgID = msgid
l.Ts = time.Now().Unix()
s.sendUserActionLog(l)
}
}
func (s *Service) actsmsproc() {
defer s.waiter.Done()
var (
err error
msgid string
)
for {
m, ok := <-s.actSms
if !ok {
log.Info("actsmsproc exit!")
return
}
if m.Mobile == "" {
if m.Country, m.Mobile, err = s.userMobile(m.Mid); err != nil {
continue
}
}
if m.Country == "" || m.Mobile == "" {
log.Error("invalid country or mobile, info(%+v)", m)
continue
}
content := _contentRe.ReplaceAllString(m.Content, "*")
l := &smsmdl.ModelUserActionLog{Mobile: m.Mobile, Content: content, Type: smsmdl.TypeActSms, Action: smsmdl.UserActionTypeSend}
if m.Country == smsmdl.CountryChina {
for i := 0; i < s.providers; i++ {
s.actp.Lock()
p := s.actp.Value.(model.Provider)
s.actp.Ring = s.actp.Next()
s.actp.Unlock()
l.Provider = p.GetPid()
if msgid, err = p.SendActSms(context.Background(), m); err == nil {
break
}
dao.PromInfo(fmt.Sprintf("service:retry act china %d", l.Provider))
log.Error("retry send act sms(%v) platform(%d) error(%v)", m, l.Provider, err)
}
} else {
for i := 0; i < s.providers; i++ {
s.intep.Lock()
p := s.intep.Value.(model.Provider)
s.intep.Ring = s.intep.Next()
s.intep.Unlock()
l.Provider = p.GetPid()
if msgid, err = p.SendInternationalSms(context.Background(), m); err == nil {
break
}
dao.PromInfo(fmt.Sprintf("service:retry act international %d", l.Provider))
log.Error("retry send act international sms(%v) platform(%d)", m, l.Provider, err)
}
}
if err == nil {
l.Status = smsmdl.UserActionSendSuccessStatus
l.Desc = smsmdl.UserActionSendSuccessDesc
dao.PromInfo(fmt.Sprintf("service:act china success %d", l.Provider))
log.Info("send act sms(%v) platform(%d) success", m, l.Provider)
} else {
l.Status = smsmdl.UserActionSendFailedStatus
l.Desc = smsmdl.UserActionSendFailedDesc
dao.PromError("service:actSms")
log.Error("send act sms(%v) error(%v)", m, err)
s.cache.Do(context.Background(), func(ctx context.Context) {
s.dao.SendWechat(fmt.Sprintf("sms-job send msg(%d) error(%v)", m.ID, err))
})
}
l.MsgID = msgid
l.Ts = time.Now().Unix()
s.sendUserActionLog(l)
}
}
func (s *Service) actbatchproc() {
defer s.waiter.Done()
var (
err error
mids []string
country string
mobile string
msgid string
)
for {
m, ok := <-s.batchSms
if !ok {
log.Info("actbatchproc exit!")
return
}
if m.Mobile == "" && m.Mid != "" {
mids = strings.Split(m.Mid, ",")
var mobiles []string
for _, midStr := range mids {
if country, mobile, err = s.userMobile(midStr); err != nil {
continue
}
if country == "" || mobile == "" {
log.Error("invalid country or mobile, code(%s) mid(%s) country(%s) mobile(%s)", m.Code, midStr, country, mobile)
continue
}
if country != smsmdl.CountryChina {
continue
}
mobiles = append(mobiles, mobile)
}
m.Mobile = strings.Join(mobiles, ",")
}
if m.Mobile == "" {
continue
}
content := _contentRe.ReplaceAllString(m.Content, "*")
l := &smsmdl.ModelUserActionLog{Mobile: m.Mobile, Content: content, Type: smsmdl.TypeActSms, Action: smsmdl.UserActionTypeSend, Ts: time.Now().Unix()}
send := &smsmdl.ModelSend{Mobile: m.Mobile, Content: m.Content, Type: smsmdl.TypeActSms}
for i := 0; i < s.providers; i++ {
s.batchp.Lock()
p := s.batchp.Value.(model.Provider)
s.batchp.Ring = s.batchp.Next()
s.batchp.Unlock()
l.Provider = p.GetPid()
if msgid, err = p.SendBatchActSms(context.Background(), send); err == nil {
break
}
dao.PromInfo(fmt.Sprintf("service:retry batch %d", l.Provider))
log.Error("retry send act batch sms(%v) platform(%d)", m, l.Provider, err)
}
if err == nil {
dao.PromInfo(fmt.Sprintf("service:batch success %d", l.Provider))
log.Info("send act batch sms(%v) platform(%d) success", m, l.Provider)
l.Status = smsmdl.UserActionSendSuccessStatus
l.Desc = smsmdl.UserActionSendSuccessDesc
} else {
dao.PromError("service:actBatchSms")
log.Error("send act batch sms(%v) error(%v)", m, err)
s.cache.Do(context.Background(), func(ctx context.Context) {
s.dao.SendWechat(fmt.Sprintf("sms-job send msg(%d) error(%v)", m.ID, err))
})
l.Status = smsmdl.UserActionSendFailedStatus
l.Desc = smsmdl.UserActionSendFailedDesc
}
l.MsgID = msgid
l.Ts = time.Now().Unix()
s.sendUserActionLog(l)
}
}
func (s *Service) userMobile(midStr string) (country, mobile string, err error) {
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
log.Error("userMobile parse mid(%s) error(%v)", midStr, err)
return
}
if mid <= 0 {
log.Error("userMobile invalid mid(%s)", midStr)
return
}
var um *model.UserMobile
for i := 0; i < _retry; i++ {
if um, err = s.dao.UserMobile(context.Background(), mid); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
if err != nil {
log.Error("UserMobile mid(%d) error(%v)", mid, err)
return
}
country = um.CountryCode
mobile = um.Mobile
return
}
func (s *Service) monitorproc() {
if env.DeployEnv != env.DeployEnvProd {
return
}
var smsCount int64
for {
time.Sleep(time.Duration(s.c.Sms.MonitorProcDuration))
if s.smsCount-smsCount == 0 {
msg := fmt.Sprintf("sms-job sms did not consume within %s seconds", time.Duration(s.c.Sms.MonitorProcDuration).String())
s.dao.SendWechat(msg)
log.Warn(msg)
}
smsCount = s.smsCount
}
}