210 lines
5.7 KiB
Go
210 lines
5.7 KiB
Go
|
package node
|
|||
|
|
|||
|
import (
|
|||
|
"admin/lib/xlog"
|
|||
|
"admin/lib/xos"
|
|||
|
"fmt"
|
|||
|
"github.com/gin-gonic/gin"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
type IBootConfigContent interface {
|
|||
|
GetLogConfig() *LogBootConfig
|
|||
|
OnReload(first bool, oldContent string)
|
|||
|
}
|
|||
|
|
|||
|
// Node 调度器,调度多个app
|
|||
|
type Node struct {
|
|||
|
// app全局启动参数
|
|||
|
bootFlags struct {
|
|||
|
globalBootFlag *CommonBootFlags
|
|||
|
exBootFlag interface{}
|
|||
|
}
|
|||
|
// app全局配置文件
|
|||
|
bootConfigFile struct {
|
|||
|
globalBootConfigFileContent IBootConfigContent // app全局配置文件内容结构体指针,为空没有配置文件解析
|
|||
|
globalBootConfigParser func(in []byte, out interface{}) error // 配置文件解析函数,默认yaml
|
|||
|
}
|
|||
|
|
|||
|
preInitFuncs []pair // 节点node全局的调用方自定义初始化方法,早于节点初始化(初始化起服配置、日志后)
|
|||
|
initFuncs []pair // 节点node全局的调用方自定义初始化方法,晚于节点初始化(初始化起服配置、日志后)、早于各个app初始化
|
|||
|
postFuncs []pair // 节点node全局的调用方自定义启动所有app之后执行的方法
|
|||
|
adis []*ApplicationDescInfo // app的描述信息列表,用来生成apps
|
|||
|
apps []*Application // 可绑定多个app
|
|||
|
tracer *gin.Engine // app全局监控服务,为prometheus、pprof共用
|
|||
|
}
|
|||
|
|
|||
|
// NewNode
|
|||
|
func NewNode(appOptions ...NodeOption) *Node {
|
|||
|
node := new(Node)
|
|||
|
node.bootFlags.globalBootFlag = GlobalBootFlags
|
|||
|
node.applyOptions(appOptions...)
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
// AddPreInitTask Node自身初始化任务,在启动APP逻辑之前执行
|
|||
|
func (node *Node) AddPreInitTask(desc string, task Task) *Node {
|
|||
|
node.preInitFuncs = append(node.preInitFuncs, pair{desc, task})
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
// AddInitTask Node自身初始化任务,在启动APP逻辑之前执行
|
|||
|
func (node *Node) AddInitTask(desc string, task Task) *Node {
|
|||
|
node.initFuncs = append(node.initFuncs, pair{desc, task})
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
// AddInitTask Node自身初始化任务,在启动APP逻辑之前执行
|
|||
|
func (node *Node) AddPostTask(desc string, task Task) *Node {
|
|||
|
node.postFuncs = append(node.postFuncs, pair{desc, task})
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
// GetBootFlags 获取节点全局的启动参数信息,即./node -node_id 123 -service_name game的值
|
|||
|
func (node *Node) GetBootFlags() *CommonBootFlags {
|
|||
|
return node.bootFlags.globalBootFlag
|
|||
|
}
|
|||
|
|
|||
|
// GetExBootFlags 获取调用方自定义的全局启动参数
|
|||
|
func (node *Node) GetExBootFlags() interface{} {
|
|||
|
return node.bootFlags.exBootFlag
|
|||
|
}
|
|||
|
|
|||
|
// GetBootConfigContent 获取注册启动配置文件app.yaml内容
|
|||
|
func (node *Node) GetBootConfigContent() IBootConfigContent {
|
|||
|
return node.bootConfigFile.globalBootConfigFileContent
|
|||
|
}
|
|||
|
|
|||
|
func (node *Node) applyOptions(options ...NodeOption) *Node {
|
|||
|
for _, option := range options {
|
|||
|
option.Apply(node)
|
|||
|
}
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
// ApplyOptions 应用一些节点配置项
|
|||
|
func (node *Node) ApplyOptions(options ...NodeOption) *Node {
|
|||
|
node.applyOptions(options...)
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
// WithApp 节点注入app
|
|||
|
func (node *Node) WithApp(appDescInfoList ...*ApplicationDescInfo) *Node {
|
|||
|
for _, adi := range appDescInfoList {
|
|||
|
node.withAppDescInfo(adi)
|
|||
|
}
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
func (node *Node) Run() error {
|
|||
|
// 初始化node
|
|||
|
node.initialize()
|
|||
|
|
|||
|
defer xlog.CatchWithInfo("run node panic")
|
|||
|
|
|||
|
// 启动调度器
|
|||
|
type waitInfo struct {
|
|||
|
desc string
|
|||
|
app *Application
|
|||
|
err error
|
|||
|
}
|
|||
|
waitChan := make(chan waitInfo, 1)
|
|||
|
|
|||
|
// 运行trace server
|
|||
|
go func() {
|
|||
|
tracerPort := node.bootFlags.globalBootFlag.TracePort
|
|||
|
xlog.Noticef("trace server listen on %v", tracerPort)
|
|||
|
err := node.tracer.Run(":" + tracerPort)
|
|||
|
if err != nil {
|
|||
|
waitChan <- waitInfo{"trace server", nil, err}
|
|||
|
}
|
|||
|
}()
|
|||
|
|
|||
|
// 初始化各个app
|
|||
|
wg := &sync.WaitGroup{}
|
|||
|
wg.Add(len(node.apps))
|
|||
|
for i, app := range node.apps {
|
|||
|
go func(app *Application, initFunc AppInitFunc) {
|
|||
|
if initFunc != nil {
|
|||
|
err := initFunc(app)
|
|||
|
if err != nil {
|
|||
|
errInfo := fmt.Errorf("application[%v] init return error[%v]", app.Name, err)
|
|||
|
waitChan <- waitInfo{app.Name, app, errInfo}
|
|||
|
} else {
|
|||
|
xlog.Noticef("application[%v] initialize ok", app.Name)
|
|||
|
}
|
|||
|
}
|
|||
|
wg.Done()
|
|||
|
err := app.run()
|
|||
|
if err != nil {
|
|||
|
// 返回调度器的报错
|
|||
|
waitChan <- waitInfo{app.Name, app, err}
|
|||
|
}
|
|||
|
}(app, node.adis[i].initFunc)
|
|||
|
}
|
|||
|
|
|||
|
// for _, app := range node.apps {
|
|||
|
// go func(app *Application) {
|
|||
|
// err := app.run()
|
|||
|
// if err != nil {
|
|||
|
// // 返回调度器的报错
|
|||
|
// waitChan <- waitInfo{app.Name, app, err}
|
|||
|
// }
|
|||
|
// }(app)
|
|||
|
// }
|
|||
|
wg.Wait()
|
|||
|
|
|||
|
// 初始化逻辑
|
|||
|
for _, j := range node.postFuncs {
|
|||
|
curErr := j.value.(Task)()
|
|||
|
if curErr != nil {
|
|||
|
err := fmt.Errorf("node run post task(%s) return error:%v", j.key, curErr)
|
|||
|
panic(err)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
watchSignChan := xos.WatchSignal1()
|
|||
|
|
|||
|
defer node.Stop()
|
|||
|
|
|||
|
select {
|
|||
|
case signal := <-watchSignChan:
|
|||
|
// 优雅停服,监听某些信号
|
|||
|
xlog.Noticef("Application receive signal(%v), will graceful stop", signal)
|
|||
|
return nil
|
|||
|
case errInfo := <-waitChan:
|
|||
|
err := fmt.Errorf("Application receive Node(%v) stop with error:%v", errInfo.desc, errInfo.err)
|
|||
|
xlog.Errorf(err.Error())
|
|||
|
return err
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (node *Node) Stop() {
|
|||
|
for _, app := range node.apps {
|
|||
|
app.stop()
|
|||
|
}
|
|||
|
time.Sleep(3 * time.Second)
|
|||
|
}
|
|||
|
|
|||
|
// WithNode 添加调度器
|
|||
|
func (node *Node) withAppDescInfo(adi *ApplicationDescInfo) *Node {
|
|||
|
node.adis = append(node.adis, adi)
|
|||
|
return node
|
|||
|
}
|
|||
|
|
|||
|
func (node *Node) initApps() error {
|
|||
|
for i, app := range node.apps {
|
|||
|
if node.adis[i].initFunc != nil {
|
|||
|
err := node.adis[i].initFunc(app)
|
|||
|
if err != nil {
|
|||
|
return fmt.Errorf("application[%v] init return error[%v]", app.Name, err)
|
|||
|
} else {
|
|||
|
xlog.Noticef("application[%v] initialize ok", app.Name)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return nil
|
|||
|
}
|