You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.7 KiB
101 lines
3.7 KiB
package svccfg
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
|
|
"yunyan/comm"
|
|
"yunyan/lego/core"
|
|
"yunyan/lego/core/cbase"
|
|
"yunyan/lego/sys/log"
|
|
)
|
|
|
|
// configComp 注册集群内的配置下发处理器。args/reply 用普通 struct——rpcx 走 MsgPack,无需 pb 类型。
|
|
type configComp struct {
|
|
cbase.ModuleCompBase
|
|
module *SvcCfg
|
|
service comm.IService
|
|
}
|
|
|
|
func (this *configComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) {
|
|
if err = this.ModuleCompBase.Init(service, module, comp, opt); err != nil {
|
|
return
|
|
}
|
|
this.module = module.(*SvcCfg)
|
|
this.service = service.(comm.IService)
|
|
return
|
|
}
|
|
|
|
func (this *configComp) Start() (err error) {
|
|
if err = this.ModuleCompBase.Start(); err != nil {
|
|
return
|
|
}
|
|
if err = this.service.Register(string(comm.Rpc_ReloadModuleConfig), this.Rpc_ReloadModuleConfig); err != nil {
|
|
return
|
|
}
|
|
// reset 处理器各服务都注册,但只有属主会真的执行(见下)——注册在非属主上是为了给出明确的拒绝理由,
|
|
// 而不是让调用方收到"方法不存在"这种含糊的 rpc 错误。
|
|
if err = this.service.Register(string(comm.Rpc_ResetModuleConfig), this.Rpc_ResetModuleConfig); err != nil {
|
|
return
|
|
}
|
|
log.Infof("[SvcCfg] 业务配置下发处理器已注册 service=%s owner=%v reloaders=%v",
|
|
this.service.GetType(), this.service.GetType() == comm.ModuleConfigOwner, comm.HasModuleReloaders())
|
|
return
|
|
}
|
|
|
|
func (this *configComp) instance() string {
|
|
host, _ := os.Hostname()
|
|
if host == "" {
|
|
host = "unknown"
|
|
}
|
|
return this.service.GetType() + "@" + host
|
|
}
|
|
|
|
// Rpc_ReloadModuleConfig 重读业务库、热替换本服务持有的 sys 客户端。
|
|
// 失败信息放在 reply.Err 而非 rpc error:这样 api 汇总时能区分「某个服务重载失败」与「整条 rpc 调不通」。
|
|
func (this *configComp) Rpc_ReloadModuleConfig(ctx context.Context, args *comm.ReloadModuleConfigReq, reply *comm.ModuleConfigResp) (err error) {
|
|
reply.Service, reply.Instance = this.service.GetType(), this.instance()
|
|
if !comm.HasModuleReloaders() {
|
|
reply.Skipped = true // 本服务不持有任何业务凭据客户端(如 gateway/timer),什么也不用做
|
|
return
|
|
}
|
|
results, e := comm.DoReloadModuleConfig()
|
|
if e != nil {
|
|
reply.Err = e.Error()
|
|
return
|
|
}
|
|
reply.Results = results
|
|
log.Infof("[SvcCfg] 已重载业务配置 service=%s reason=%s modules=%d", reply.Service, args.Reason, len(results))
|
|
return
|
|
}
|
|
|
|
// Rpc_ResetModuleConfig 把某模块还原为**本服务配置文件**里的初始值。
|
|
//
|
|
// 只有配置属主(comm.ModuleConfigOwner=home)会执行:yaml 每服务一份,非属主的 yaml 不是权威初始值,
|
|
// 让它们也写库会互相覆盖。还原后仍需由 api 扇出 reload,让其余服务重读库。
|
|
func (this *configComp) Rpc_ResetModuleConfig(ctx context.Context, args *comm.ResetModuleConfigReq, reply *comm.ModuleConfigResp) (err error) {
|
|
reply.Service, reply.Instance = this.service.GetType(), this.instance()
|
|
if reply.Service != comm.ModuleConfigOwner {
|
|
reply.Err = "本服务(" + reply.Service + ")不是业务配置属主(" + comm.ModuleConfigOwner + "),不能从配置文件还原"
|
|
return
|
|
}
|
|
if args.Module == "" {
|
|
reply.Err = "缺少要还原的模块名"
|
|
return
|
|
}
|
|
// "*" = 整库还原(升级/迁移把库写脏后的整体恢复);否则只还原单个模块。
|
|
var results []comm.ModuleApplyResult
|
|
var e error
|
|
if args.Module == comm.ModuleResetAll {
|
|
results, e = comm.DoResetAllModuleConfigToFile()
|
|
} else {
|
|
results, e = comm.DoResetModuleConfigToFile(args.Module)
|
|
}
|
|
if e != nil {
|
|
reply.Err = e.Error()
|
|
return
|
|
}
|
|
reply.Results = results
|
|
log.Infof("[SvcCfg] 已还原为配置文件初始值 service=%s module=%s", reply.Service, args.Module)
|
|
return
|
|
}
|
|
|