|
@@ -4,10 +4,14 @@ import (
|
|
|
"context"
|
|
|
"crypto/md5"
|
|
|
"encoding/hex"
|
|
|
+ "git.nspix.com/golang/micro/broker"
|
|
|
"git.nspix.com/golang/micro/gateway/cli"
|
|
|
+ "git.nspix.com/golang/micro/internal/rbtree"
|
|
|
"git.nspix.com/golang/micro/stats/prometheusbackend"
|
|
|
"git.nspix.com/golang/micro/utils/machineid"
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
|
+ "math"
|
|
|
+ "math/rand"
|
|
|
"net"
|
|
|
hp "net/http"
|
|
|
"net/http/pprof"
|
|
@@ -15,6 +19,7 @@ import (
|
|
|
"os/signal"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
+ "sync/atomic"
|
|
|
"syscall"
|
|
|
"time"
|
|
|
|
|
@@ -28,6 +33,10 @@ import (
|
|
|
"git.nspix.com/golang/micro/utils/unsafestr"
|
|
|
)
|
|
|
|
|
|
+var (
|
|
|
+ tickSequence int64
|
|
|
+)
|
|
|
+
|
|
|
type Service struct {
|
|
|
opts *Options
|
|
|
ctx context.Context
|
|
@@ -42,10 +51,12 @@ type Service struct {
|
|
|
cliSvr *cli.Server
|
|
|
upTime time.Time
|
|
|
client *Client
|
|
|
+ timer *time.Timer
|
|
|
+ tickTree *rbtree.Tree
|
|
|
environment string
|
|
|
}
|
|
|
|
|
|
-func (svr *Service) wrapSync(f func()) {
|
|
|
+func (svr *Service) async(f func()) {
|
|
|
svr.wg.Add(1)
|
|
|
go func() {
|
|
|
f()
|
|
@@ -53,36 +64,73 @@ func (svr *Service) wrapSync(f func()) {
|
|
|
}()
|
|
|
}
|
|
|
|
|
|
-func (svr *Service) eventLoop() {
|
|
|
+func (svr *Service) worker() {
|
|
|
var (
|
|
|
- err error
|
|
|
- registryTicker *time.Ticker
|
|
|
- collectTicker *time.Ticker
|
|
|
+ err error
|
|
|
+ ticker *time.Ticker
|
|
|
)
|
|
|
- registryTicker = time.NewTicker(time.Second * 20)
|
|
|
- collectTicker = time.NewTicker(time.Hour * 6)
|
|
|
+ ticker = time.NewTicker(time.Second * 20)
|
|
|
defer func() {
|
|
|
- collectTicker.Stop()
|
|
|
- registryTicker.Stop()
|
|
|
+ ticker.Stop()
|
|
|
}()
|
|
|
for {
|
|
|
select {
|
|
|
- case <-registryTicker.C:
|
|
|
+ case <-svr.timer.C:
|
|
|
+ node := svr.tickTree.Iterator()
|
|
|
+ if node == nil {
|
|
|
+ svr.timer.Reset(math.MaxInt64)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ tick := node.Value.(*tickPtr)
|
|
|
+ if tick.next.Before(time.Now()) {
|
|
|
+ svr.tickTree.Delete(node.Key)
|
|
|
+ if !tick.options.Canceled {
|
|
|
+ if atomic.CompareAndSwapInt32(&tick.running, 0, 1) {
|
|
|
+ svr.async(func() {
|
|
|
+ tick.callback(tick.options.Context)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ next := node.Next()
|
|
|
+ if next == nil {
|
|
|
+ svr.timer.Reset(math.MaxInt64)
|
|
|
+ } else {
|
|
|
+ svr.timer.Reset(next.Value.(*tickPtr).next.Sub(time.Now()))
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ svr.timer.Reset(tick.next.Sub(time.Now()))
|
|
|
+ }
|
|
|
+ case <-ticker.C:
|
|
|
if !svr.opts.DisableRegister {
|
|
|
if err = svr.registry.Register(svr.node); err != nil {
|
|
|
log.Warnf("registry service %s error: %s", svr.opts.Name, err.Error())
|
|
|
}
|
|
|
}
|
|
|
- case <-collectTicker.C:
|
|
|
- if svr.opts.EnableReport {
|
|
|
- _ = defaultReporter.Do(svr.opts.Name)
|
|
|
- }
|
|
|
case <-svr.ctx.Done():
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//DeferTick 定时执行一个任务
|
|
|
+func (svr *Service) DeferTick(duration time.Duration, callback HandleTickerFunc, opts ...TickOption) int64 {
|
|
|
+ t := &tickPtr{
|
|
|
+ sequence: atomic.AddInt64(&tickSequence, 1),
|
|
|
+ next: time.Now().Add(duration),
|
|
|
+ options: &TickOptions{},
|
|
|
+ callback: callback,
|
|
|
+ }
|
|
|
+ for _, optFunc := range opts {
|
|
|
+ optFunc(t.options)
|
|
|
+ }
|
|
|
+ if t.options.Context == nil {
|
|
|
+ t.options.Context = svr.ctx
|
|
|
+ }
|
|
|
+ svr.timer.Reset(0)
|
|
|
+ svr.tickTree.Insert(t, t)
|
|
|
+ return t.sequence
|
|
|
+}
|
|
|
+
|
|
|
//Handle 处理函数
|
|
|
func (svr *Service) Handle(method string, cb HandleFunc, opts ...HandleOption) {
|
|
|
//disable cli default
|
|
@@ -117,6 +165,7 @@ func (svr *Service) Handle(method string, cb HandleFunc, opts ...HandleOption) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+//NewRequest 创建一个请求
|
|
|
func (svr *Service) NewRequest(name, method string, body interface{}) (req *Request, err error) {
|
|
|
return &Request{
|
|
|
ServiceName: name,
|
|
@@ -211,12 +260,12 @@ func (svr *Service) instance() *registry.ServiceNode {
|
|
|
func (svr *Service) startHTTPServe() (err error) {
|
|
|
l := gateway.NewListener(svr.listener.Addr())
|
|
|
if err = svr.gateway.Attaches([][]byte{[]byte("GET"), []byte("POST"), []byte("PUT"), []byte("DELETE"), []byte("OPTIONS")}, l); err == nil {
|
|
|
- svr.wrapSync(func() {
|
|
|
+ svr.async(func() {
|
|
|
if err = svr.httpSvr.Serve(l); err != nil {
|
|
|
log.Warnf("http serve error: %s", err.Error())
|
|
|
}
|
|
|
+ log.Infof("http server stopped")
|
|
|
})
|
|
|
-
|
|
|
svr.httpSvr.Handle("GET", "/healthy", func(ctx *http.Context) (err error) {
|
|
|
return ctx.Success(map[string]interface{}{
|
|
|
"id": svr.node.ID,
|
|
@@ -251,10 +300,11 @@ func (svr *Service) startHTTPServe() (err error) {
|
|
|
func (svr *Service) startRPCServe() (err error) {
|
|
|
l := gateway.NewListener(svr.listener.Addr())
|
|
|
if err = svr.gateway.Attach([]byte("RPC"), l); err == nil {
|
|
|
- svr.wrapSync(func() {
|
|
|
+ svr.async(func() {
|
|
|
if err = svr.rpcSvr.Serve(l); err != nil {
|
|
|
log.Warnf("rpc serve start error: %s", err.Error())
|
|
|
}
|
|
|
+ log.Infof("rpc server stopped")
|
|
|
})
|
|
|
log.Infof("attach rpc listener success")
|
|
|
} else {
|
|
@@ -266,10 +316,11 @@ func (svr *Service) startRPCServe() (err error) {
|
|
|
func (svr *Service) startCliServe() (err error) {
|
|
|
l := gateway.NewListener(svr.listener.Addr())
|
|
|
if err = svr.gateway.Attach([]byte("CLI"), l); err == nil {
|
|
|
- svr.wrapSync(func() {
|
|
|
+ svr.async(func() {
|
|
|
if err = svr.cliSvr.Serve(l); err != nil {
|
|
|
log.Warnf("cli serve start error: %s", err.Error())
|
|
|
}
|
|
|
+ log.Infof("cli server stopped")
|
|
|
})
|
|
|
log.Infof("attach cli listener success")
|
|
|
} else {
|
|
@@ -307,15 +358,13 @@ func (svr *Service) prepare() (err error) {
|
|
|
}
|
|
|
log.Infof("server listen on: %s", svr.listener.Addr())
|
|
|
svr.gateway = gateway.New(svr.listener, svr.opts.EnableStats)
|
|
|
- svr.wrapSync(func() {
|
|
|
+ svr.async(func() {
|
|
|
svr.gateway.Run(svr.ctx)
|
|
|
})
|
|
|
-
|
|
|
//开启HTTP服务
|
|
|
if svr.opts.EnableHttp {
|
|
|
err = svr.startHTTPServe()
|
|
|
}
|
|
|
-
|
|
|
//开启RCP服务
|
|
|
if svr.opts.EnableRPC {
|
|
|
err = svr.startRPCServe()
|
|
@@ -326,12 +375,18 @@ func (svr *Service) prepare() (err error) {
|
|
|
}
|
|
|
}
|
|
|
svr.node = svr.instance()
|
|
|
- svr.wrapSync(func() {
|
|
|
- svr.eventLoop()
|
|
|
+ svr.async(func() {
|
|
|
+ svr.worker()
|
|
|
})
|
|
|
if !svr.opts.DisableRegister {
|
|
|
_ = svr.registry.Register(svr.node)
|
|
|
}
|
|
|
+ if svr.opts.EnableReport {
|
|
|
+ rn := rand.Int31n(48) + 60
|
|
|
+ svr.DeferTick(time.Hour*time.Duration(rn), func(ctx context.Context) {
|
|
|
+ _ = defaultReporter.Do(svr.opts.Name)
|
|
|
+ })
|
|
|
+ }
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -348,11 +403,26 @@ func (svr *Service) destroy() (err error) {
|
|
|
if svr.listener != nil {
|
|
|
if err = svr.listener.Close(); err != nil {
|
|
|
log.Warnf(err.Error())
|
|
|
+ } else {
|
|
|
+ log.Infof("listener closed")
|
|
|
}
|
|
|
}
|
|
|
if err = svr.client.Close(); err != nil {
|
|
|
log.Warnf(err.Error())
|
|
|
}
|
|
|
+ svr.timer.Stop()
|
|
|
+ if svr.tickTree.Size() > 0 {
|
|
|
+ log.Warnf("num of %d defer tick dropped", svr.tickTree.Size())
|
|
|
+ node := svr.tickTree.Iterator()
|
|
|
+ for node != nil {
|
|
|
+ tick := node.Value.(*tickPtr)
|
|
|
+ if tick.options.MustBeExecute {
|
|
|
+ tick.callback(tick.options.Context)
|
|
|
+ }
|
|
|
+ node = node.Next()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ svr.wg.Wait()
|
|
|
log.Infof("service stopped")
|
|
|
return
|
|
|
}
|
|
@@ -365,6 +435,8 @@ func (svr *Service) Run() (err error) {
|
|
|
if err = svr.prepare(); err != nil {
|
|
|
return
|
|
|
}
|
|
|
+ //设置全局的代理组件
|
|
|
+ broker.SetGlobal(broker.NewInPrcBus(svr.ctx))
|
|
|
//start server
|
|
|
if svr.opts.Server != nil {
|
|
|
if err = svr.opts.Server.Start(svr.ctx); err != nil {
|
|
@@ -398,6 +470,8 @@ func New(opts ...Option) *Service {
|
|
|
cliSvr: cli.New(),
|
|
|
rpcSvr: rpc.NewServer(),
|
|
|
registry: o.registry,
|
|
|
+ timer: time.NewTimer(math.MaxInt64),
|
|
|
+ tickTree: rbtree.NewTree(),
|
|
|
client: NewClient(o.registry),
|
|
|
environment: EnvironmentHost,
|
|
|
}
|