前言

最近补 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.Init0Init (1)
engine.RunInit (1)Running (2)
engine.ShutdownRunning (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 实现一个优雅退出功能提供参考和思路,如果哪里有问题或者错误欢迎评论或者私信,以上。