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
|
||
}
|