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 }