uniugm/admin/lib/node/node.go
2025-04-18 17:17:23 +08:00

210 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}