Skip to content

refactor(config): 重构 Etcd 配置监听机制#369

Open
2451965602 wants to merge 5 commits into
west2-online:mainfrom
2451965602:main
Open

refactor(config): 重构 Etcd 配置监听机制#369
2451965602 wants to merge 5 commits into
west2-online:mainfrom
2451965602:main

Conversation

@2451965602
Copy link
Copy Markdown

自查 PR 结构

  • PR 标题符合这个格式: <type>(optional scope): <description>

  • 此 PR 标题的描述以用户为导向,足够清晰,其他人可以理解。

  • 我已经对所有 commit 提供了签名(GPG 密钥签名、SSH 密钥签名)

  • 这个 PR 属于强制变更/破坏性更改

如果是,请在 PR 标题中添加 BREAKING CHANGE 前缀,并在 PR 描述中详细说明。

这个 PR 的类型是什么?

refactor(config): 重构 Etcd 配置监听机制

这个 PR 做了什么 / 我们为什么需要这个 PR?

(可选)这个 PR 解决了哪个/些 issue?

对 Reviewer 预留的一些提醒

- 替换 Viper 内置的 Etcd 监听器
- 使用 `go.etcd.io/etcd/client/v3` 客户端实现配置热更新
- 提高配置变更检测的可靠性和灵活性
@2451965602 2451965602 requested review from a team, jiuxia211 and ozline as code owners December 13, 2025 16:32
Comment thread config/config.go Outdated
Copy link
Copy Markdown
Member

@ozline ozline left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

单独开一个协程没有问题,但是如果我们需要关闭这个服务,如何通知协程关闭?

你可能需要引入一个 context

@2451965602
Copy link
Copy Markdown
Author

单独开一个协程没有问题,但是如果我们需要关闭这个服务,如何通知协程关闭?

你可能需要引入一个 context

在什么情况下要单独关闭该服务,在etcd环境下运行时对配置的热重载应该没必要关闭,而当使用了k8s环境,该协程不会启动,也不会有关闭该协程的需求

@ozline
Copy link
Copy Markdown
Member

ozline commented Dec 15, 2025

单独开一个协程没有问题,但是如果我们需要关闭这个服务,如何通知协程关闭?
你可能需要引入一个 context

在什么情况下要单独关闭该服务,在etcd环境下运行时对配置的热重载应该没必要关闭,而当使用了k8s环境,该协程不会启动,也不会有关闭该协程的需求

这个是优雅退出的一部分,如果没有传递 ctx,在服务关闭的过程中这个 goroutine 仍然在运行,最后的结果类似于「强制掐断」,如果携带了 ctx,我们可以通过 ctx 传递服务已关闭(这个通常直接通过一个支持死亡的 ctx 来做就可以了),在服务优雅关闭过程中我们让上下文先关闭,之后再退出就行

因为这个 pr 不是紧急改动,你可以稍微改多一些

- 为非 k8s 环境的服务启动 Etcd 配置热更新监听
- 在服务关闭时通过 context 取消 Etcd 监听 goroutine
- 优化 Etcd 客户端关闭逻辑,确保资源释放
@2451965602
Copy link
Copy Markdown
Author

因为要使用kitex和hertz框架下的优雅关闭,考虑到在init里实现较为困难,在这里采取在main函数中判断当前环境,非k8s状态下创建一个可取消的ctx并开启一个协程监听配置文件变化,并在 OnShutdown与RegisterShutdownHook 下注册ctx取消函数

@mutezebra
Copy link
Copy Markdown
Member

因为要使用kitex和hertz框架下的优雅关闭,考虑到在init里实现较为困难,在这里采取在main函数中判断当前环境,非k8s状态下创建一个可取消的ctx并开启一个协程监听配置文件变化,并在 OnShutdown与RegisterShutdownHook 下注册ctx取消函数

可以问下为什么要在 非 k8s 场景在才有相关改动吗?k8s 场景会带来什么影响?

@2451965602
Copy link
Copy Markdown
Author

因为要使用kitex和hertz框架下的优雅关闭,考虑到在init里实现较为困难,在这里采取在main函数中判断当前环境,非k8s状态下创建一个可取消的ctx并开启一个协程监听配置文件变化,并在 OnShutdown与RegisterShutdownHook 下注册ctx取消函数

可以问下为什么要在 非 k8s 场景在才有相关改动吗?k8s 场景会带来什么影响?

修改前 Etcd出现配置文件更新后Viper获取不到配置文件更改的信息 导致无法进行热更新,修改的主要依据是Etcd会在配置文件变化时向客户端发出事件,从而通知Viper重新读取最新的配置文件并进行重映射。k8s下配置文件并不依赖Etcd,应该可以使用Viper的监听,不需要启动Etcd的监听

@ozline
Copy link
Copy Markdown
Member

ozline commented Jan 16, 2026

现在我来康康,哎开源就很容易一拖拖很久,工作了有 KPI 绩效考勤卡着你不会让你拖这么久

@ozline
Copy link
Copy Markdown
Member

ozline commented Jan 16, 2026

@2451965602 尝试一下 git merge 来解决文件冲突哈,这个会非常常用,尽量自己解决冲突

一般以 main 分支的代码为准,但不要一股脑都用 main 的代码

Comment thread cmd/classroom/main.go Outdated

func main() {
var watcherCancel context.CancelFunc
if os.Getenv("DEPLOY_ENV") != "k8s" {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这种复用 2 次以上的常量写到 contants 里

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

其他模块也是这样

Comment thread config/config.go Outdated
}
case <-ctx.Done():
logger.Infof("Stopping etcd config watcher.")
err = cli.Close()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个部分改用 defer 实现,一般这种类似于 fs 操作的,我们会在创建后立刻写一个 defer,这样可读性也好,而且 cr 的时候可以一眼看到确实关闭了

Copy link
Copy Markdown
Member

@ozline ozline left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

稍微改改就行

# Conflicts:
#	cmd/academic/main.go
#	cmd/classroom/main.go
#	cmd/course/main.go
#	cmd/oa/main.go
#	cmd/paper/main.go
#	cmd/user/main.go
#	cmd/version/main.go
- 将硬编码的 "DEPLOY_ENV" 替换为 `constants.DeployEnv` 常量
- 确保 etcd 客户端在函数退出时正确关闭
@2451965602 2451965602 requested a review from mutezebra as a code owner January 17, 2026 06:41
Comment thread cmd/academic/main.go
if os.Getenv(constants.DeployEnv) != "k8s" {
watcherCtx, cancel := context.WithCancel(context.Background())
watcherCancel = cancel
go config.StartEtcdWatcher(watcherCtx, serviceName)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我重新看了一下整个链条,我尝试问一个设计的修改:

这里对于每一个模块(需要注意的是这个 pr 由于比较久了,缺少了新增的 captcha 模块),都使用了一模一样的代码,我们能否尝试把这些代码挪到 config.go 配置模块里呢?

这样在每一个模块的 main 函数(或者说更前面的init()函数,init()执行顺序是优先于 main()的)里只需要调用一个 config 的初始化函数就可以了?

因为我看现在的逻辑,会在init()执行时初始化配置,再一直到 main()时开始监听,这个我觉得可以合并一下

你可以看看方案是否有必要

Copy link
Copy Markdown
Member

@ozline ozline left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

还有一个额外的问题:我们实际场景是容器化部署的,从这个 env 的传参以及目前的修改来看,我好像没找到地方传入这个环境变量

这个环境变量是容器环境现在就有的吗?如果不是,你可能需要修改一下容器的启动配置

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants