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,23 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/seq-server/cmd:all-srcs",
"//app/service/main/seq-server/conf:all-srcs",
"//app/service/main/seq-server/dao:all-srcs",
"//app/service/main/seq-server/http:all-srcs",
"//app/service/main/seq-server/model:all-srcs",
"//app/service/main/seq-server/rpc/client:all-srcs",
"//app/service/main/seq-server/rpc/server:all-srcs",
"//app/service/main/seq-server/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,47 @@
# seq-server
### v1.5.1
> 1.dao层ut
### v1.5.0
> 1.grpc auth
### v1.4.3
> 1.增加discovery注册
### v1.4.2
> 1.close时增加rpc.Close
### v1.4.1
>1.迁移BM
>2.迁移新配置中心
>3.增加rpc client new discovery
### v1.3.1
> 1.add register
### v1.3.0
> 1.迁移到主站目录下
### v1.2.3
> 1.seq去掉idc支持
> 2.添加maxseq设置接口
### v1.2.2
> 1.添加rpc sharding
### v1.2.1
> 1.修复maxseq更新内存中的值
### v1.2.0
> 1.支持ID int32
> 2.添加ping检查
### v1.1.1
> 1.ID不强自增
> 2.预备去除proxy
### v1.1.0
> 1.rename db
### v1.0.0
> 1.项目初始化

View File

@@ -0,0 +1,8 @@
# Owner
peiyifei
# Author
peiyifei
# Reviewer
haoguanwei

View File

@@ -0,0 +1,13 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- peiyifei
labels:
- main
- service
- service/main/seq-server
options:
no_parent_owners: true
reviewers:
- haoguanwei
- peiyifei

View File

@@ -0,0 +1,10 @@
#### seq-server
##### 项目简介
> 1.发号器
##### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common

View File

@@ -0,0 +1,47 @@
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 = ["seq-server-test.toml"],
importpath = "go-common/app/service/main/seq-server/cmd",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/conf:go_default_library",
"//app/service/main/seq-server/http:go_default_library",
"//app/service/main/seq-server/rpc/server:go_default_library",
"//app/service/main/seq-server/service:go_default_library",
"//library/conf/env:go_default_library",
"//library/log:go_default_library",
"//library/naming:go_default_library",
"//library/naming/discovery:go_default_library",
"//library/net/ip:go_default_library",
"//library/net/trace: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,82 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/seq-server/conf"
"go-common/app/service/main/seq-server/http"
rpc "go-common/app/service/main/seq-server/rpc/server"
"go-common/app/service/main/seq-server/service"
"go-common/library/conf/env"
"go-common/library/log"
"go-common/library/naming"
"go-common/library/naming/discovery"
xip "go-common/library/net/ip"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("seq-server start")
// service init
svr := service.New(conf.Conf)
rpcSvr := rpc.New(conf.Conf, svr)
http.Init(conf.Conf, svr)
// start discovery register
var (
err error
cancel context.CancelFunc
)
if env.IP == "" {
ip := xip.InternalIP()
dis := discovery.New(nil)
ins := &naming.Instance{
Zone: env.Zone,
Env: env.DeployEnv,
AppID: "seq.server",
Addrs: []string{
"http://" + ip + ":" + env.HTTPPort,
"gorpc://" + ip + ":" + env.GORPCPort,
},
}
if cancel, err = dis.Register(context.Background(), ins); err != nil {
panic(err)
}
}
// end discovery register
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("seq-server get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
if cancel != nil {
cancel()
}
rpcSvr.Close()
time.Sleep(time.Second * 2)
log.Info("seq-server exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,84 @@
# This is a TOML document. Boom.
version = "1.0.0"
user = "nobody"
pid = "/tmp/seq-server.pid"
dir = "./"
perf = "127.0.0.1:7110"
family = "seq-server"
tick = "2s"
seqSvrs = ["0.0.0.0:7111"]
[log]
dir = "/data/log/seq-server/"
[log.agent]
family = "seq-server"
taskID = "000161"
proto = "unixgram"
addr = "/var/run/lancer/collector.sock"
chan = 10240
[tracer]
family = "seq-server"
proto = "unixgram"
addr = "/var/run/dapper-collect/dapper-collect.sock"
[identify]
whiteAccessKey = "a2a1eb0ac97d6ba08b85aa0151528f34"
whiteMid = 23675773
[identify.app]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
[identify.host]
auth = "http://passport.bilibili.co"
secret = "http://open.bilibili.co"
[identify.httpClient]
key = "7c7ac0db1aa05587"
secret = "9a6d62d93290c5f771ad381e9ca23f26"
dial = "30ms"
timeout = "100ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://open.bilibili.co/api/getsecret" = {timeout = "500ms"}
[multiHTTP]
[multiHTTP.inner]
addrs = ["0.0.0.0:7112"]
[db]
[db.number]
name = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/sequence?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 50
idle = 10
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[db.number.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[rpcServer2]
discoverOff = false
[[rpcServer2.servers]]
proto = "tcp"
addr = "0.0.0.0:7111"
weight = 10
[rpcServer2.zookeeper]
root = "/microservice/seq-server/"
addrs = ["172.18.33.172:2181"]
timeout = "30s"

View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/service/main/seq-server/conf",
tags = ["automanaged"],
deps = [
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/trace: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"],
)

View File

@@ -0,0 +1,90 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/rpc"
"go-common/library/net/trace"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
Conf = &Config{}
client *conf.Client
)
type Config struct {
// base
SeqSvrs []string
Tick time.Duration
// rpc server
RPCServer *rpc.ServerConfig
// http
BM *bm.ServerConfig
// log
Log *log.Config
// tracer
Tracer *trace.Config
// db
DB *DB
}
type DB struct {
Number *sql.Config
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config.
func Init() (err error) {
if confPath != "" {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
err = remote()
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
}

View File

@@ -0,0 +1,52 @@
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",
"seq_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"seq.go",
],
importpath = "go-common/app/service/main/seq-server/dao",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/conf:go_default_library",
"//app/service/main/seq-server/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/log: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,39 @@
package dao
import (
"context"
"go-common/app/service/main/seq-server/conf"
"go-common/library/database/sql"
"go-common/library/log"
)
// Dao is seq-server dao.
type Dao struct {
c *conf.Config
// db
db *sql.DB
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
// db
db: sql.NewMySQL(c.DB.Number),
}
return
}
// Ping ping db
func (d *Dao) Ping() (err error) {
if err = d.db.Ping(context.TODO()); err != nil {
log.Error("d.db.Ping error(%v)", err)
}
return
}
// Close close resource.
func (d *Dao) Close() {
d.db.Close()
}

View File

@@ -0,0 +1,34 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/service/main/seq-server/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.common-arch.seq-server")
flag.Set("conf_token", "3d6e1df5016b46baef2db5dd70add25e")
flag.Set("tree_id", "5986")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,72 @@
package dao
import (
"context"
"database/sql"
"time"
"go-common/app/service/main/seq-server/model"
"go-common/library/log"
)
const (
_allSQL = "SELECT id,max_seq,step,token,perch,ctime,mtime FROM business"
_maxSeqSQL = "SELECT max_seq FROM business WHERE id=?"
_upMaxSeqSQL = "UPDATE business SET max_seq=? WHERE id=? AND max_seq=?"
_upMaxSeqTokenSQL = "UPDATE business SET max_seq=?,step=? WHERE id=? AND token=?"
)
// All get all seq
func (d *Dao) All(c context.Context) (bs map[int64]*model.Business, err error) {
rows, err := d.db.Query(c, _allSQL)
if err != nil {
log.Error("d.db.Query(%s) error(%v)", _allSQL, err)
return
}
bs = make(map[int64]*model.Business)
defer rows.Close()
for rows.Next() {
b := new(model.Business)
if err = rows.Scan(&b.ID, &b.MaxSeq, &b.Step, &b.Token, &b.Perch, &b.CTime, &b.MTime); err != nil {
log.Error("rows.Scan error(%v)")
return
}
b.BenchTime = b.CTime.Time().UnixNano() / int64(time.Millisecond)
b.LastTimestamp = time.Now().UnixNano() / int64(time.Millisecond)
bs[b.ID] = b
}
return
}
// MaxSeq return current max seq.
func (d *Dao) MaxSeq(c context.Context, businessID int64) (maxSeq int64, err error) {
row := d.db.QueryRow(c, _maxSeqSQL, businessID)
if err = row.Scan(&maxSeq); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// UpMaxSeq update max seq by businessID.
func (d *Dao) UpMaxSeq(c context.Context, businessID, maxSeq, lastSeq int64) (rows int64, err error) {
res, err := d.db.Exec(c, _upMaxSeqSQL, maxSeq, businessID, lastSeq)
if err != nil {
log.Error("d.db.Exec(%s, %d, %d) error(%v)", _upMaxSeqSQL, maxSeq, businessID)
return
}
return res.RowsAffected()
}
// UpMaxSeqToken update max seq by businessID and token.
func (d *Dao) UpMaxSeqToken(c context.Context, businessID, maxSeq, step int64, token string) (rows int64, err error) {
res, err := d.db.Exec(c, _upMaxSeqTokenSQL, maxSeq, step, businessID, token)
if err != nil {
log.Error("d.db.Exec(%s, %d, %d) error(%v)", _upMaxSeqSQL, maxSeq, businessID)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,68 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAll(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("All", t, func(ctx convey.C) {
bs, err := d.All(c)
ctx.Convey("Then err should be nil.bs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(bs, convey.ShouldNotBeNil)
})
})
}
func TestDaoMaxSeq(t *testing.T) {
var (
c = context.TODO()
businessID = int64(2)
)
convey.Convey("MaxSeq", t, func(ctx convey.C) {
maxSeq, err := d.MaxSeq(c, businessID)
ctx.Convey("Then err should be nil.maxSeq should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(maxSeq, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpMaxSeq(t *testing.T) {
var (
c = context.TODO()
businessID = int64(1)
maxSeq = int64(10)
lastSeq = int64(2)
)
convey.Convey("UpMaxSeq", t, func(ctx convey.C) {
rows, err := d.UpMaxSeq(c, businessID, maxSeq, lastSeq)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpMaxSeqToken(t *testing.T) {
var (
c = context.TODO()
businessID = int64(1)
maxSeq = int64(10)
step = int64(2)
token = ""
)
convey.Convey("UpMaxSeqToken", t, func(ctx convey.C) {
rows, err := d.UpMaxSeqToken(c, businessID, maxSeq, step, token)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"seq.go",
],
importpath = "go-common/app/service/main/seq-server/http",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/conf:go_default_library",
"//app/service/main/seq-server/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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,54 @@
package http
import (
"net/http"
"go-common/app/service/main/seq-server/conf"
"go-common/app/service/main/seq-server/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
seqSvc *service.Service
vrfSvc *verify.Verify
)
// Init init http router.
func Init(c *conf.Config, s *service.Service) {
seqSvc = s
vrfSvc = verify.New(nil)
en := bm.DefaultServer(c.BM)
innerRouter(en)
// init internal server
if err := en.Start(); err != nil {
log.Error("xhttp.Serve error(%v)", err)
panic(err)
}
}
// innerRouter init inner router.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
seq := e.Group("/x/internal/seq", vrfSvc.Verify)
{
seq.POST("/id", seqID)
seq.POST("/id32", seqID32)
seq.POST("/maxseq", maxSeq)
}
}
// ping check server ok.
func ping(c *bm.Context) {
if err := seqSvc.Ping(c); err != nil {
log.Error("seq-server ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// register check server ok.
func register(c *bm.Context) {
c.JSON(nil, nil)
}

View File

@@ -0,0 +1,83 @@
package http
import (
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
// seqID return id
func seqID(c *bm.Context) {
params := c.Request.Form
bsIDStr := params.Get("businessID")
// check params
bsID, err := strconv.ParseInt(bsIDStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
token := params.Get("token")
if token == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(seqSvc.ID(c, bsID, token))
}
// seqID32 return id32
func seqID32(c *bm.Context) {
params := c.Request.Form
bsIDStr := params.Get("businessID")
// check params
bsID, err := strconv.ParseInt(bsIDStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
token := params.Get("token")
if token == "" {
c.JSON(nil, ecode.RequestErr)
return
}
id, err := seqSvc.ID32(c, bsID, token)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(id, nil)
}
// maxSeq update maxseq.
func maxSeq(c *bm.Context) {
params := c.Request.Form
bsIDStr := params.Get("businessID")
maxSeqStr := params.Get("maxseq")
stepStr := params.Get("step")
token := params.Get("token")
// check params
bsID, err := strconv.ParseInt(bsIDStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
maxSeq, err := strconv.ParseInt(maxSeqStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
step, err := strconv.ParseInt(stepStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if token == "" {
c.JSON(nil, ecode.RequestErr)
return
}
if err = seqSvc.UpMaxSeq(c, bsID, maxSeq, step, token); err != nil {
c.JSON(nil, err)
return
}
c.JSON(maxSeq, nil)
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["model.go"],
importpath = "go-common/app/service/main/seq-server/model",
tags = ["automanaged"],
deps = ["//library/time: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,44 @@
package model
import (
"errors"
"sync"
"go-common/library/time"
)
// ErrBusinessNotReady business is not ready.
var ErrBusinessNotReady = errors.New("error buiness is not ready")
// ArgBusiness rpc arg
type ArgBusiness struct {
BusinessID int64
Token string
}
// Key rpc sharding key.
func (a *ArgBusiness) Key() int64 {
return a.BusinessID
}
// Business business seq struct
type Business struct {
ID int64
CurSeq int64
MaxSeq int64
Step int64
Perch int64
BenchTime int64
LastTimestamp int64
Token string
CTime time.Time
MTime time.Time
Mutex sync.Mutex
}
// SeqVersion seq-server version
type SeqVersion struct {
IDC int64
SvrNum int64
SvrTime int64
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["client_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//app/service/main/seq-server/model:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "go-common/app/service/main/seq-server/rpc/client",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/model:go_default_library",
"//library/net/rpc: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,41 @@
package client
import (
"context"
"go-common/app/service/main/seq-server/model"
"go-common/library/net/rpc"
)
const (
_ID = "RPC.ID"
_IDInt32 = "RPC.ID32"
)
const (
_appid = "seq.server"
)
// Service2 is seq rpc client.
type Service2 struct {
client *rpc.Client2
}
// New2 new a seq rpc client.
func New2(c *rpc.ClientConfig) (s *Service2) {
s = &Service2{}
s.client = rpc.NewDiscoveryCli(_appid, c)
return
}
// ID get id.
func (s *Service2) ID(c context.Context, arg *model.ArgBusiness) (id int64, err error) {
err = s.client.Call(c, _ID, arg, &id)
return
}
// ID32 get id32.
func (s *Service2) ID32(c context.Context, arg *model.ArgBusiness) (id int32, err error) {
err = s.client.Call(c, _IDInt32, arg, &id)
return
}

View File

@@ -0,0 +1,51 @@
package client
import (
"context"
"testing"
"time"
"go-common/app/service/main/seq-server/model"
)
func TestDynamic(t *testing.T) {
s := New2(nil)
time.Sleep(5 * time.Second)
testID(t, s)
testID32(t, s)
}
func testID(t *testing.T, s *Service2) {
res := make(map[int64]struct{})
for i := 0; i < 10000; i++ {
id, err := s.ID(context.TODO(), &model.ArgBusiness{BusinessID: 7, Token: "RA8yy0RjDCBTGgFUha4hPOnhxfXvM8hR"})
if err != nil {
t.Errorf("s.ID error(%v)", err)
continue
}
if _, ok := res[id]; ok {
t.Errorf("s.ID repeat id:%d", id)
t.FailNow()
}
res[id] = struct{}{}
t.Logf("got ID(%d)", id)
}
}
func testID32(t *testing.T, s *Service2) {
res := make(map[int32]struct{})
for i := 0; i < 10000; i++ {
id, err := s.ID32(context.TODO(), &model.ArgBusiness{BusinessID: 7, Token: "RA8yy0RjDCBTGgFUha4hPOnhxfXvM8hR"})
if err != nil {
t.Errorf("s.ID error(%v)", err)
continue
}
if _, ok := res[id]; ok {
t.Errorf("s.ID repeat id:%d", id)
t.FailNow()
}
res[id] = struct{}{}
t.Logf("got ID(%d)", id)
}
}

View 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 = ["rpc.go"],
importpath = "go-common/app/service/main/seq-server/rpc/server",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/conf:go_default_library",
"//app/service/main/seq-server/model:go_default_library",
"//app/service/main/seq-server/service:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/context: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,58 @@
package server
import (
"go-common/app/service/main/seq-server/conf"
"go-common/app/service/main/seq-server/model"
"go-common/app/service/main/seq-server/service"
"go-common/library/net/rpc"
"go-common/library/net/rpc/context"
)
// RPC rpc.
type RPC struct {
s *service.Service
}
// New creates rpc server.
func New(c *conf.Config, s *service.Service) (svr *rpc.Server) {
r := &RPC{s: s}
svr = rpc.NewServer(c.RPCServer)
if err := svr.Register(r); err != nil {
panic(err)
}
return
}
// Auth check connection success.
func (r *RPC) Auth(c context.Context, arg *rpc.Auth, res *struct{}) (err error) {
return
}
// Ping check connection success.
func (r *RPC) Ping(c context.Context, arg *struct{}, res *struct{}) (err error) {
if err = r.s.Ping(c); err != model.ErrBusinessNotReady {
err = nil
}
return
}
// ID return id.
func (r *RPC) ID(c context.Context, a *model.ArgBusiness, res *int64) (err error) {
*res, err = r.s.ID(c, a.BusinessID, a.Token)
return
}
// ID32 return id32.
func (r *RPC) ID32(c context.Context, a *model.ArgBusiness, res *int32) (err error) {
*res, err = r.s.ID32(c, a.BusinessID, a.Token)
return
}
// CheckVersion check db health.
func (r *RPC) CheckVersion(c context.Context, arg *struct{}, res *model.SeqVersion) (err error) {
var seqVer *model.SeqVersion
if seqVer, err = r.s.CheckVersion(c); err == nil {
*res = *seqVer
}
return
}

View File

@@ -0,0 +1,53 @@
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/service/main/seq-server/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"number.go",
"seq.go",
"service.go",
],
importpath = "go-common/app/service/main/seq-server/service",
tags = ["automanaged"],
deps = [
"//app/service/main/seq-server/conf:go_default_library",
"//app/service/main/seq-server/dao:go_default_library",
"//app/service/main/seq-server/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc:go_default_library",
"//library/time: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,61 @@
package service
import (
"context"
"time"
"go-common/app/service/main/seq-server/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_maxSeq = 1024
)
// tilNextMillis spin wait till next millisecond.
func tilNextMillis(lastTimestamp int64) (now int64) {
now = time.Now().UnixNano() / int64(time.Millisecond)
for now <= lastTimestamp {
now = time.Now().UnixNano() / int64(time.Millisecond)
}
return now
}
// ID get id
func (s *Service) ID(c context.Context, businessID int64, token string) (id int64, err error) {
s.bl.RLock()
b, ok := s.bs[businessID]
s.bl.RUnlock()
if !ok || b.Token != token {
err = ecode.NothingFound
log.Error("businessID(%d) not found!", businessID)
return
}
b.Mutex.Lock()
defer b.Mutex.Unlock()
now := time.Now().UnixNano() / int64(time.Millisecond)
if b.LastTimestamp > now {
err = ecode.ServerErr
log.Error("clock is moving backwards. Rejecting requests until %d.", b.LastTimestamp)
return
}
if b.LastTimestamp == now {
b.CurSeq++
if b.CurSeq >= _maxSeq {
b.CurSeq = 0
now = tilNextMillis(b.LastTimestamp)
}
} else {
b.CurSeq = 0
}
b.LastTimestamp = now
id = b.Perch<<62 | (now-b.BenchTime)<<19 | b.CurSeq<<6 | s.svrNum<<s.idcLen | s.idc
return
}
// CheckVersion check server version
func (s *Service) CheckVersion(c context.Context) (ver *model.SeqVersion, err error) {
ver = &model.SeqVersion{IDC: s.idc, SvrNum: s.svrNum, SvrTime: time.Now().Unix()}
return
}

View File

@@ -0,0 +1,71 @@
package service
import (
"context"
"fmt"
"go-common/app/service/main/seq-server/model"
"go-common/library/ecode"
)
const _nextStepRetry = 3
func (s *Service) nextStep(c context.Context, b *model.Business) (err error) {
var (
n int
lastSeq, rows int64
)
for {
if lastSeq, err = s.db.MaxSeq(c, b.ID); err != nil {
return
}
if rows, err = s.db.UpMaxSeq(c, b.ID, lastSeq+b.Step, lastSeq); err != nil {
return
}
if rows > 0 {
b.CurSeq = lastSeq
b.MaxSeq = lastSeq + b.Step
break
}
if n++; n > _nextStepRetry {
err = fmt.Errorf("get the next step failed(id:%d maxseq:%d step:%d)", b.ID, b.MaxSeq, b.Step)
return
}
}
return
}
// ID32 get id int32.
func (s *Service) ID32(c context.Context, businessID int64, token string) (id int32, err error) {
s.bl.RLock()
b, ok := s.bs[businessID]
s.bl.RUnlock()
if !ok || b.Token != token {
err = ecode.NothingFound
return
}
b.Mutex.Lock()
// NOTE: make sure curSeq begin with maxSeq when start from 0
if b.CurSeq == 0 || b.CurSeq+1 > b.MaxSeq {
if err = s.nextStep(c, b); err != nil {
b.Mutex.Unlock()
return
}
}
b.CurSeq++
id = int32(b.CurSeq)
b.Mutex.Unlock()
return
}
// UpMaxSeq update max seq by buisinessID and token.
func (s *Service) UpMaxSeq(c context.Context, businessID, maxSeq, step int64, token string) (err error) {
rows, err := s.db.UpMaxSeqToken(c, businessID, maxSeq, step, token)
if err != nil {
return
}
if rows <= 0 {
err = fmt.Errorf("update maxSeq failed(businessID:%d maxSeq:%d)", businessID, maxSeq)
}
return
}

View File

@@ -0,0 +1,121 @@
package service
import (
"context"
"fmt"
"os"
"strconv"
"sync"
"time"
"go-common/app/service/main/seq-server/conf"
"go-common/app/service/main/seq-server/dao"
"go-common/app/service/main/seq-server/model"
"go-common/library/log"
"go-common/library/net/rpc"
xtime "go-common/library/time"
)
// Service is service.
type Service struct {
c *conf.Config
db *dao.Dao
bs map[int64]*model.Business
bl sync.RWMutex
idc int64
idcLen uint
svrNum int64
lastTimestamp int64
}
// New new a Service and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
// dao
db: dao.New(c),
bs: make(map[int64]*model.Business),
lastTimestamp: time.Now().UnixNano() / int64(time.Millisecond),
}
var (
idc string
svrNum string
err error
)
idc = os.Getenv("SEQ_IDC")
if s.idc, err = strconv.ParseInt(idc, 10, 64); err != nil || s.idc > 3 {
panic(fmt.Sprintf("SEQ_IDC config(%s) error(%v)", idc, err))
}
svrNum = os.Getenv("SEQ_SERVERNUM")
if s.svrNum, err = strconv.ParseInt(svrNum, 10, 64); err != nil || s.svrNum > 15 {
panic(fmt.Sprintf("SEQ_SERVERNUM config(%s) or error(%v)", svrNum, err))
}
s.idcLen = uint(len(strconv.FormatInt(s.idc, 2)))
svrLen := uint(len(strconv.FormatInt(s.svrNum, 2)))
if s.idcLen+svrLen > 6 {
panic("ids + svrNum must <= 6")
}
for k, addr := range s.c.SeqSvrs {
client := rpc.Dial(addr, xtime.Duration(100*time.Millisecond), nil)
var (
_noArg = struct{}{}
res *model.SeqVersion
err error
)
if err = client.Call(context.TODO(), "RPC.CheckVersion", _noArg, &res); err != nil {
log.Error("client.Call(RPC.CheckVersion) addr(%s) error(%v)", addr, err)
continue
}
now := time.Now().Unix()
if now-res.SvrTime > 2 || res.SvrTime-now < -2 {
panic(fmt.Sprintf("myTime(%d) svrTime(%d) svrNum(%d),time is running out too much", now, res.SvrTime, res.SvrNum))
}
if res.IDC == s.idc && res.SvrNum == s.svrNum {
panic(fmt.Sprintf("server(%d) idc and svrNum is same", k))
}
client.Close()
}
s.loadSeqs()
go s.loadproc()
return
}
func (s *Service) loadproc() {
for {
time.Sleep(time.Duration(s.c.Tick))
s.loadSeqs()
}
}
// Close resource.
func (s *Service) Close() {
s.db.Close()
}
func (s *Service) loadSeqs() (err error) {
var bs map[int64]*model.Business
if bs, err = s.db.All(context.TODO()); err != nil {
return
}
for id, b := range bs {
s.bl.Lock()
if _, ok := s.bs[id]; !ok {
s.bs[id] = b
s.bl.Unlock()
continue
}
s.bl.Unlock()
}
return
}
// Ping ping service is ok.
func (s *Service) Ping(c context.Context) (err error) {
if err = s.db.Ping(); err != nil {
return
}
if len(s.bs) == 0 {
err = model.ErrBusinessNotReady
}
return
}

View File

@@ -0,0 +1,36 @@
package service
import (
"context"
"flag"
"fmt"
"path/filepath"
"testing"
"go-common/app/service/main/seq-server/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
dir, _ := filepath.Abs("../cmd/seq-server-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
}
func Test_Close(t *testing.T) {
Convey("Close", t, func() {
s.Close()
})
}
func Test_ID(t *testing.T) {
Convey("ID", t, func() {
fmt.Println(s.ID(context.TODO(), 10, "Nf9phmDdzjTMW9M5V8YQuLpVTwhvn5IO"))
})
}