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

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
}