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,59 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"bin_log.go",
"encrypt_trans.go",
"passport.go",
"prom.go",
"service.go",
],
importpath = "go-common/app/job/main/passport-game-cloud/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/passport-game-cloud/conf:go_default_library",
"//app/job/main/passport-game-cloud/dao:go_default_library",
"//app/job/main/passport-game-cloud/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
"//vendor/github.com/go-sql-driver/mysql:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"prom_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/job/main/passport-game-cloud/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey: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,72 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/passport-game-cloud/model"
"go-common/library/log"
)
const (
_memberTableUpdateDuration = time.Second * 1
)
func (s *Service) processMemberInfo(bmsg *model.BMsg) {
n := new(model.Info)
if err := json.Unmarshal(bmsg.New, n); err != nil {
log.Error("failed to parse binlog new, json.Unmarshal(%s) error(%v)", string(bmsg.New), err)
return
}
s.memberInterval.Prom(context.TODO(), bmsg.MTS)
switch bmsg.Action {
case "insert":
s.addMemberInfo(context.TODO(), n)
s.delInfoCache(context.TODO(), n.Mid)
case "update":
old := new(model.Info)
if err := json.Unmarshal(bmsg.Old, old); err != nil {
log.Error("failed to parse binlog old, json.Unmarshal(%s) error(%v)", string(bmsg.Old), err)
return
}
if n.Equals(old) {
return
}
s.addMemberInfo(context.TODO(), n)
s.delInfoCache(context.TODO(), n.Mid)
case "delete":
s.delMemberInfo(context.TODO(), n.Mid)
s.delInfoCache(context.TODO(), n.Mid)
}
}
func (s *Service) addMemberInfo(c context.Context, info *model.Info) (err error) {
for {
if _, err = s.d.AddMemberInfo(c, info); err == nil {
break
}
time.Sleep(_memberTableUpdateDuration)
}
return
}
func (s *Service) delMemberInfo(c context.Context, mid int64) (err error) {
for {
if _, err = s.d.DelMemberInfo(c, mid); err == nil {
break
}
time.Sleep(_memberTableUpdateDuration)
}
return
}
func (s *Service) delInfoCache(c context.Context, mid int64) (err error) {
for i := 0; i < _accountCacheRetryCount; i++ {
if err = s.d.DelInfoCache(c, mid); err == nil {
break
}
time.Sleep(_accountCacheRetryDuration)
}
return
}

View File

@@ -0,0 +1,137 @@
package service
import (
"context"
"encoding/json"
"strings"
"time"
"go-common/app/job/main/passport-game-cloud/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
func (s *Service) binlogconsumeproc() {
mergeRoutineNum := int64(s.c.Group.BinLog.Num)
for {
msg, ok := <-s.binLogDataBus.Messages()
if !ok {
log.Error("binlogconsumeproc closed")
return
}
// marked head to first commit
m := &message{data: msg}
s.mu.Lock()
if s.head == nil {
s.head = m
s.last = m
} else {
s.last.next = m
s.last = m
}
s.mu.Unlock()
bmsg := new(model.BMsg)
if err := json.Unmarshal(msg.Value, bmsg); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(msg.Value), err)
continue
}
mid := int64(0)
if bmsg.Table == _asoAccountTable {
t := new(model.OriginAsoAccount)
if err := json.Unmarshal(bmsg.New, t); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(bmsg.New), err)
continue
}
mid = t.Mid
bmsg.MTS = s.asoAccountInterval.MTS(context.TODO(), t.Mtime)
} else if strings.HasPrefix(bmsg.Table, _tokenTablePrefix) {
t := new(model.OriginPerm)
if err := json.Unmarshal(bmsg.New, t); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(bmsg.New), err)
continue
}
mid = t.Mid
bmsg.MTS = s.tokenInterval.MTS(context.TODO(), t.Mtime)
} else if strings.HasPrefix(bmsg.Table, _memberTablePrefix) {
t := new(model.OriginMember)
if err := json.Unmarshal(bmsg.New, t); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(bmsg.New), err)
continue
}
mid = t.Mid
bmsg.MTS = s.memberInterval.MTS(context.TODO(), t.Mtime)
}
m.object = bmsg
// use specify goroutine to merge messages
s.binLogMergeChans[mid%mergeRoutineNum] <- m
log.Info("binlogconsumeproc table:%s key:%s partition:%d offset:%d", bmsg.Table, msg.Key, msg.Partition, msg.Offset)
}
}
func (s *Service) binlogcommitproc() {
commits := make(map[int32]*databus.Message, s.c.Group.BinLog.Size)
for {
done := <-s.binLogDoneChan
// merge partitions to commit offset
for _, d := range done {
d.done = true
}
s.mu.Lock()
for ; s.head != nil && s.head.done; s.head = s.head.next {
commits[s.head.data.Partition] = s.head.data
}
s.mu.Unlock()
for k, m := range commits {
log.Info("binlogcommitproc committed, key:%s partition:%d offset:%d", m.Key, m.Partition, m.Offset)
m.Commit()
delete(commits, k)
}
}
}
func (s *Service) binlogmergeproc(c chan *message) {
var (
max = s.c.Group.BinLog.Size
merges = make([]*model.BMsg, 0, max)
marked = make([]*message, 0, max)
ticker = time.NewTicker(time.Duration(s.c.Group.BinLog.Ticker))
)
for {
select {
case msg, ok := <-c:
if !ok {
log.Error("binlogmergeproc closed")
return
}
p, assertOk := msg.object.(*model.BMsg)
if assertOk {
merges = append(merges, p)
}
marked = append(marked, msg)
if len(marked) < max && len(merges) < max {
continue
}
case <-ticker.C:
}
if len(merges) > 0 {
s.process(merges)
merges = make([]*model.BMsg, 0, max)
}
if len(marked) > 0 {
s.binLogDoneChan <- marked
marked = make([]*message, 0, max)
}
}
}
func (s *Service) process(bmsgs []*model.BMsg) {
for _, bmsg := range bmsgs {
if bmsg.Table == _asoAccountTable {
s.processUserInfo(bmsg)
} else if strings.HasPrefix(bmsg.Table, _tokenTablePrefix) {
s.processToken(bmsg)
} else if strings.HasPrefix(bmsg.Table, _memberTablePrefix) {
s.processMemberInfo(bmsg)
}
}
}

View File

@@ -0,0 +1,110 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/passport-game-cloud/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
func (s *Service) encrypttransconsumeproc() {
var (
mergeRoutineNum = int64(s.c.Group.EncryptTrans.Num)
msgs = s.encryptTransDataBus.Messages()
)
for {
msg, ok := <-msgs
if !ok {
log.Error("encrypttransconsumeproc closed")
return
}
// marked head to first commit
m := &message{data: msg}
s.asoMu.Lock()
if s.asoHead == nil {
s.asoHead = m
s.asoLast = m
} else {
s.asoLast.next = m
s.asoLast = m
}
s.asoMu.Unlock()
p := new(model.PMsg)
if err := json.Unmarshal(msg.Value, p); err != nil {
log.Error("encrypttransconsumeproc unmarshal failed, json.Unmarshal(%s) error(%v)", msg.Value, err)
continue
}
if p.Table == _asoAccountTable {
p.MTS = s.transInterval.MTS(context.TODO(), p.Data.Mtime)
}
m.object = p
s.encryptTransMergeChans[p.Data.Mid%mergeRoutineNum] <- m
log.Info("encrypttransconsumeproc key:%s partition:%d offset:%d", msg.Key, msg.Partition, msg.Offset)
}
}
func (s *Service) encrypttranscommitproc() {
commits := make(map[int32]*databus.Message, s.c.Group.EncryptTrans.Size)
for {
done := <-s.encryptTransDoneChan
for _, d := range done {
d.done = true
}
s.asoMu.Lock()
for ; s.asoHead != nil && s.asoHead.done; s.asoHead = s.asoHead.next {
commits[s.asoHead.data.Partition] = s.asoHead.data
}
s.asoMu.Unlock()
for k, m := range commits {
log.Info("encrypttranscommitproc committed, key:%s partition:%d offset:%d", m.Key, m.Partition, m.Offset)
m.Commit()
delete(commits, k)
}
}
}
func (s *Service) encrypttransmergeproc(c chan *message) {
var (
max = s.c.Group.EncryptTrans.Size
merges = make([]*model.PMsg, 0, max)
marked = make([]*message, 0, max)
ticker = time.NewTicker(time.Duration(s.c.Group.EncryptTrans.Ticker))
)
for {
select {
case msg, ok := <-c:
if !ok {
log.Error("encrypttransmergeproc closed")
return
}
p, assertOK := msg.object.(*model.PMsg)
if assertOK {
merges = append(merges, p)
}
marked = append(marked, msg)
if len(marked) < max && len(merges) < max {
continue
}
case <-ticker.C:
}
if len(merges) > 0 {
s.processAsoAcc(merges)
merges = make([]*model.PMsg, 0, max)
}
if len(marked) > 0 {
s.encryptTransDoneChan <- marked
marked = make([]*message, 0, max)
}
}
}
func (s *Service) processAsoAcc(pmsgs []*model.PMsg) {
for _, p := range pmsgs {
if p.Action != "" && p.Table == _asoAccountTable {
s.processAsoAccSub(p)
}
}
}

View File

@@ -0,0 +1,267 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/passport-game-cloud/model"
"go-common/library/log"
"github.com/go-sql-driver/mysql"
"github.com/pkg/errors"
)
const (
_userTableUpdateDuration = time.Second
_mySQLErrCodeDuplicateEntry = 1062
_tokenTableUpdateRetryCount = 3
_tokenTableUpdateDuration = time.Second
_tokenTablePrefix = "aso_app_perm"
_tokenCacheRetryCount = 3
_tokenCacheRetryDuration = time.Second
_notifyGameRetryCount = 3
_notifyGameRetryDuration = time.Second
)
func (s *Service) processUserInfo(bmsg *model.BMsg) {
n := new(model.Info)
if err := json.Unmarshal(bmsg.New, n); err != nil {
log.Error("failed to parse binlog new, json.Unmarshal(%s) error(%v)", string(bmsg.New), err)
return
}
s.asoAccountInterval.Prom(context.TODO(), bmsg.MTS)
switch bmsg.Action {
case "insert":
s.addMemberInit(context.TODO(), n)
s.delInfoCache(context.TODO(), n.Mid)
case "update":
old := new(model.Info)
if err := json.Unmarshal(bmsg.Old, old); err != nil {
log.Error("failed to parse binlog old, json.Unmarshal(%s) error(%v)", string(bmsg.Old), err)
return
}
if n.Equals(old) {
return
}
s.delInfoCache(context.TODO(), n.Mid)
case "delete":
s.delInfoCache(context.TODO(), n.Mid)
}
}
// sub log encryption UPDATE INSERT
func (s *Service) processAsoAccSub(msg *model.PMsg) {
n := msg.Data
flag := msg.Flag
s.transInterval.Prom(context.TODO(), msg.MTS)
switch msg.Action {
case "insert":
s.addAsoAccount(context.TODO(), n)
case "update":
s.updateAsoAccount(context.TODO(), n, flag)
case "delete":
s.delAsoAccount(context.TODO(), n.Mid)
}
s.delInfoCache(context.TODO(), n.Mid)
s.notifyGame(context.TODO(), n.Mid, "", _updateUserInfo)
}
func (s *Service) processToken(bmsg *model.BMsg) {
n := new(model.Perm)
if err := json.Unmarshal(bmsg.New, n); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", string(bmsg.New), err)
return
}
isGame := false
for _, id := range s.gameAppIDs {
if n.AppID == id {
isGame = true
break
}
}
if !isGame {
return
}
s.tokenInterval.Prom(context.TODO(), bmsg.MTS)
switch bmsg.Action {
case "insert":
s.addToken(context.TODO(), n)
s.setTokenCache(context.TODO(), n)
case "update":
old := new(model.Perm)
if err := json.Unmarshal(bmsg.Old, old); err != nil {
log.Error("failed to parse binlog old, json.Unmarshal(%s) error(%v)", string(bmsg.Old), err)
return
}
if n.Equals(old) {
return
}
s.updateToken(context.TODO(), n)
s.setTokenCache(context.TODO(), n)
case "delete":
s.delToken(context.TODO(), n.AccessToken)
s.delTokenCache(context.TODO(), n.AccessToken)
}
}
func (s *Service) addAsoAccount(c context.Context, a *model.AsoAccount) (err error) {
for {
_, err = s.d.AddAsoAccount(c, a)
if err == nil {
break
}
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("failed to add aso because of duplicate entry, value is (%v), error(%v)", a, err)
return
}
}
time.Sleep(_userTableUpdateDuration)
}
return
}
func (s *Service) updateAsoAccount(c context.Context, a *model.AsoAccount, flag int) (err error) {
for {
_, err = s.UpdateAsoAccount(c, a, flag)
if err == nil {
break
}
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("failed to update aso because of duplicate entry, value is (%v), error(%v)", a, err)
return
}
}
time.Sleep(_userTableUpdateDuration)
}
return
}
// UpdateAsoAccount update aso account.
func (s *Service) UpdateAsoAccount(c context.Context, t *model.AsoAccount, flag int) (affected int64, err error) {
if affected, err = s.d.UpdateAsoAccount(c, t); err != nil {
return
}
if flag != 1 {
return
}
mid := t.Mid
var tokens []string
if tokens, err = s.d.Tokens(c, mid); err != nil {
return
}
for _, token := range tokens {
s.delToken(c, token)
s.delTokenCache(c, token)
s.notifyGame(c, mid, token, _changePwd)
}
return
}
func (s *Service) delAsoAccount(c context.Context, mid int64) (err error) {
for {
if _, err = s.d.DelAsoAccount(c, mid); err == nil {
break
}
time.Sleep(_userTableUpdateDuration)
}
return
}
func (s *Service) addMemberInit(c context.Context, a *model.Info) (err error) {
for {
memberInfo := &model.Info{
Mid: a.Mid,
Uname: a.Uname,
Face: "",
}
err = s.addMemberInfo(c, memberInfo)
if err == nil {
break
}
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("failed to add member because of duplicate entry, error(%v)", err)
return
}
}
time.Sleep(_userTableUpdateDuration)
}
return
}
func (s *Service) setTokenCache(c context.Context, t *model.Perm) (err error) {
for i := 0; i < _tokenCacheRetryCount; i++ {
if err = s.d.SetTokenCache(c, t); err == nil {
break
}
time.Sleep(_tokenCacheRetryDuration)
}
return
}
func (s *Service) delTokenCache(c context.Context, accessToken string) (err error) {
for i := 0; i < _tokenCacheRetryCount; i++ {
if err = s.d.DelTokenCache(c, accessToken); err == nil {
break
}
time.Sleep(_tokenCacheRetryDuration)
}
return
}
func (s *Service) addToken(c context.Context, t *model.Perm) (err error) {
for i := 0; i < _tokenTableUpdateRetryCount; i++ {
_, err = s.d.AddToken(c, t)
if err == nil {
return
}
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("failed to add token because of duplicate entry, error(%v)", err)
return
}
}
time.Sleep(_tokenTableUpdateDuration)
}
return
}
func (s *Service) updateToken(c context.Context, t *model.Perm) (err error) {
for i := 0; i < _tokenTableUpdateRetryCount; i++ {
if _, err = s.d.UpdateToken(c, t); err == nil {
return
}
time.Sleep(_tokenTableUpdateDuration)
}
return
}
func (s *Service) delToken(c context.Context, accessToken string) (err error) {
for i := 0; i < _tokenTableUpdateRetryCount; i++ {
if _, err = s.d.DelToken(c, accessToken); err == nil {
return
}
time.Sleep(_tokenTableUpdateDuration)
}
return
}
func (s *Service) notifyGame(c context.Context, mid int64, token, action string) (err error) {
for i := 0; i < _notifyGameRetryCount; i++ {
if err = s.d.NotifyGame(c, mid, token, action); err == nil {
return
}
time.Sleep(_notifyGameRetryDuration)
}
return
}

View File

@@ -0,0 +1,73 @@
package service
import (
"context"
"fmt"
"time"
"go-common/library/log"
"go-common/library/stat/prom"
)
const (
_timeFormat = "2006-01-02 15:04:05"
)
var (
_names = make(map[string]struct{})
_loc = time.Now().Location()
)
// IntervalConfig interval config.
type IntervalConfig struct {
Name string
Rate int64
}
// Interval prom interval.
type Interval struct {
name string
rate int64
counter int64
}
// NewInterval new a interval instance.
func NewInterval(c *IntervalConfig) *Interval {
if _, ok := _names[c.Name]; ok {
panic(fmt.Sprintf("%s already exists", c.Name))
}
_names[c.Name] = struct{}{}
if c.Rate <= 0 {
c.Rate = 1000
}
return &Interval{
name: c.Name,
rate: c.Rate,
counter: 0,
}
}
// MTS get mtime ts from mtime str with interval's counter.
func (s *Interval) MTS(c context.Context, mtStr string) int64 {
s.counter++
if s.counter%s.rate == 0 {
return 0
}
if mtStr == "" {
return 0
}
t, err := time.ParseInLocation(_timeFormat, mtStr, _loc)
if err != nil {
log.Error("failed to parse mtime str for %s, time.ParseInLocation(%s, %s, %v) error(%v)", s.name, _timeFormat, mtStr, _loc, err)
return 0
}
return t.Unix()
}
// Prom prom interval if mts > 0.
func (s *Interval) Prom(c context.Context, mts int64) {
if mts > 0 {
prom.BusinessInfoCount.State(s.name, time.Now().Unix()-mts)
}
}

View File

@@ -0,0 +1,45 @@
package service
import (
"context"
"fmt"
"testing"
"time"
)
func TestNewInterval(t *testing.T) {
name := "counter_1"
NewInterval(&IntervalConfig{
Name: name,
Rate: 1000,
})
defer func() {
expectErrStr := fmt.Sprintf("%s already exists", name)
errStr := recover()
if errStr != expectErrStr {
t.Errorf("must painc when name is not unique, expcted %s but got %v", expectErrStr, errStr)
t.FailNow()
}
}()
NewInterval(&IntervalConfig{
Name: name,
Rate: 1000,
})
}
func TestInterval_Prom(t *testing.T) {
name := "counter_1"
itv := NewInterval(&IntervalConfig{
Name: name,
Rate: 1000,
})
count := 10
mtStr := time.Now().Format(_timeFormat)
for i := 0; i < count; i++ {
itv.Prom(context.TODO(), itv.MTS(context.TODO(), mtStr))
}
if itv.counter != int64(count) {
t.Errorf("interval counter of %s should be %d after get mts for %d times, but now it is %d", name, count, count, itv.counter)
t.FailNow()
}
}

View File

@@ -0,0 +1,152 @@
package service
import (
"context"
"sync"
"time"
"go-common/app/job/main/passport-game-cloud/conf"
"go-common/app/job/main/passport-game-cloud/dao"
"go-common/library/queue/databus"
)
const (
// cache retry count and duration
_accountCacheRetryCount = 3
_accountCacheRetryDuration = time.Second
// table and duration
_asoAccountTable = "aso_account"
_memberTablePrefix = "dede_member"
_changePwd = "changePwd"
_updateUserInfo = "updateUserInfo"
_gameAppID = int32(876)
)
// Service service.
type Service struct {
c *conf.Config
d *dao.Dao
missch chan func()
// prom
tokenInterval *Interval
memberInterval *Interval
asoAccountInterval *Interval
transInterval *Interval
gameAppIDs []int32
// bin log proc
binLogDataBus *databus.Databus
binLogMergeChans []chan *message
binLogDoneChan chan []*message
head, last *message
mu sync.Mutex
// aso acc proc
encryptTransDataBus *databus.Databus
encryptTransMergeChans []chan *message
encryptTransDoneChan chan []*message
asoHead, asoLast *message
asoMu sync.Mutex
}
type message struct {
next *message
data *databus.Message
object interface{}
done bool
}
// New new a service instance.
func New(c *conf.Config) (s *Service) {
gameAppIDs := make([]int32, 0)
gameAppIDs = append(gameAppIDs, _gameAppID)
for _, id := range c.Game.AppIDs {
if id == _gameAppID {
continue
}
gameAppIDs = append(gameAppIDs, id)
}
s = &Service{
c: c,
d: dao.New(c),
missch: make(chan func(), 10240),
// prom
tokenInterval: NewInterval(&IntervalConfig{
Name: "interval_token",
Rate: 1000,
}),
memberInterval: NewInterval(&IntervalConfig{
Name: "interval_member",
Rate: 1000,
}),
asoAccountInterval: NewInterval(&IntervalConfig{
Name: "interval_aso_account",
Rate: 1000,
}),
transInterval: NewInterval(&IntervalConfig{
Name: "interval_trans",
Rate: 1000,
}),
gameAppIDs: gameAppIDs,
binLogDataBus: databus.New(c.DataBus.BinLogSub),
binLogMergeChans: make([]chan *message, c.Group.BinLog.Num),
binLogDoneChan: make(chan []*message, c.Group.BinLog.Chan),
// aso acc proc
encryptTransDataBus: databus.New(c.DataBus.EncryptTransSub),
encryptTransMergeChans: make([]chan *message, c.Group.EncryptTrans.Num),
encryptTransDoneChan: make(chan []*message, c.Group.EncryptTrans.Chan),
}
// start bin log proc
go s.binlogcommitproc()
for i := 0; i < c.Group.BinLog.Num; i++ {
ch := make(chan *message, c.Group.BinLog.Chan)
s.binLogMergeChans[i] = ch
go s.binlogmergeproc(ch)
}
go s.binlogconsumeproc()
// start encrypt trans proc
go s.encrypttranscommitproc()
for i := 0; i < c.Group.EncryptTrans.Num; i++ {
ch := make(chan *message, c.Group.EncryptTrans.Chan)
s.encryptTransMergeChans[i] = ch
go s.encrypttransmergeproc(ch)
}
go s.encrypttransconsumeproc()
// go s.cacheproc()
return
}
//func (s *Service) addCache(f func()) {
// select {
// case s.missch <- f:
// default:
// log.Warn("cache chan full")
// }
//}
// cacheproc is a routine for executing closure.
//func (s *Service) cacheproc() {
// for {
// f := <-s.missch
// f()
// }
//}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
err = s.d.Ping(c)
return
}
// Close close service, including closing dao.
func (s *Service) Close() (err error) {
s.binLogDataBus.Close()
s.encryptTransDataBus.Close()
s.d.Close()
return
}

View File

@@ -0,0 +1,31 @@
package service
import (
"sync"
"testing"
"go-common/app/job/main/passport-game-cloud/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
once sync.Once
s *Service
)
func startService() {
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
func TestNew(t *testing.T) {
once.Do(startService)
Convey("game app ids should ok", t, func() {
So(s.gameAppIDs[0], ShouldEqual, _gameAppID)
t.Logf("s.gameAppIDs: %v", s.gameAppIDs)
})
}