前言
最近补 Golang channel 方面八股的时候发现用 channel 实现一个优雅退出功能好像不是很难,之前写的 HTTP 框架刚好也不支持优雅退出功能,于是就参考了 Hertz 优雅退出方面的代码,为我的 PIANO 补足了这个 feature。
字节跳动开源社区 CloudWeGo 开源的一款高性能 HTTP 框架,具有高易用性、高性能、高扩展性等特点。
笔者自己实现的轻量级 HTTP 框架,具有中间件,三种不同的路由(静态,通配,参数)方式,路由分组,优雅退出等功能,迭代发展中。
实现思路
os.Signalchancontext.WithTimeouttime.After
读源码
由于 Hertz 的 Hook 功能中的 ShutdownHook 是 graceful shutdown 的一环,并且 Hook 功能的实现也不是很难所以这里就一起分析了,如果不想看直接跳到后面的章节即可 :)
Hook
Hook 函数是一个通用的概念,表示某事件触发时所伴随的操作,Hertz 提供了 StartHook 和 ShutdownHook 用于在服务触发启动后和退出前注入用户自己的处理逻辑。
append
appendOnShutdown
并且设置的 StartHook 会按照声明顺序依次调用,但是 ShutdownHook 会并发的进行调用,这里的实现后面会讲。
StartHook 的执行时机
StartHook
上面是官方文档中描述的 StartHook 的执行时机,具体在源码中就是下面的代码:
h.Spin()engine.Runh.Spinengine.Runengine.OnRunengine.listenAndServe()
ShutdownHook 的执行时机
ShutdownHookserver.WithExitWaitTime
上面是官方文档中描述的 ShutdownHook 的执行时机,具体在源码中就是下面的代码:
sync.WaitGroupch
服务注册与下线的执行时机
服务注册
initOnRunHooksStartHookRegistryRegister
取消注册
ShutdownDeregisterexecuteOnShutdownHooks
Engine Status
status
statusuint32
下面列出了 Hertz Engine 状态改变的时机:
| 函数 | 状态改变前 | 状态改变后 |
|---|---|---|
| engine.Init | 0 | Init (1) |
| engine.Run | Init (1) | Running (2) |
| engine.Shutdown | Running (2) | Shutdown (3) |
| engine.Run defer | ? | Closed (4) |
atomic
优雅退出
signalToNotifysignals
engine.RunerrChwaitSignalh.Spin()engine.RunwaitSignalh.Spin()waitSignalselect
三个会触发 Shutdown 的信号区别如下:
syscall.SIGINTsyscall.SIGHUPsyscall.SIGTERM
waitSignalnilh.Spin()
context.WithTimeoutWithExitWaitTimectxShutdownch
以上就是 Hertz 优雅退出部分的源码分析,可以发现 Hertz 多次利用了协程,通过 channel 传递信号进行流程控制和信息传递,并通过 Context 的超时机制完成了整个优雅退出流程。
自己实现
说是自己实现实际上也就是代码搬运工,把 Hertz 的 graceful shutdown 及其相关功能给 PIANO 进行适配罢了ww
代码实现都差不多,一些小细节根据我个人的习惯做了修改,完整修改参考这个 commit,对 PIANO 感兴趣的话欢迎 Star !
适配 Hook
适配 Engine Status
适配 Graceful Shutdown
总结
本文通过对 Hertz 优雅退出功能的实现做了源码分析并对自己的 HTTP 框架进行了适配,希望可以帮助读者利用 channel 实现一个优雅退出功能提供参考和思路,如果哪里有问题或者错误欢迎评论或者私信,以上。