🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
通常应用在进行发布,重启或者服务器迁移时都会让应用进程关闭,我们更希望在可预知的进程关闭时,让正常处理的任务尽量处理完成后再关闭,比如数据库操作,数据同步等等,让进程关闭重启更加的平滑优雅; Orange 框架已封装了优雅退出相关处理逻辑,按照如下方式即可实现优雅退出。 ### 实现说明 - http服务基于 http 的 shutdown 方法实现; - 自定义业务逻辑基于 `signal.Notify` 信号监听,等待处理来实现; ### 快速开始 - 退出后,等待处理完成 ~~~ // 通过该方法添加相关处理逻辑, 进程退出后会等待 `ExitWaitFunDo` 中的逻辑处理完成后再退出; app.ExitWaitFunDo(func() { // run something }) ~~~ - 进程退出后置操作 ~~~ // 通过该方法可以在进程退出后调用到 `AppDefer` 中的方法 app.AppDefer(func() { // run when app shutdown }) ~~~ ### 防止僵尸进程 如果在 `ExitWaitFunDo` 和 `AppDefer` 中定义了死循环或长时间的任务,会导致进程不能正常退出或重启形成僵尸进程,为了防止此类情况,框架从底层设计上会防止该情况,进程监听到退出信号后,等待配置的指定超时时间还没处理完成进程也会强制退出; ~~~ [app] maxWaitSecond=120 # 最大等待时间 ~~~ ### 捕获退出信号 如上述等待退出相关方法无法满足特定需求时,可以通过获取退出信号的方法完成自定义需求; Orange 框架通过 golang 系统包 `signal.Notify` 方法获取退出信号,如应用中重复使用该方法会导致框架获取退出信号异常,因此框架对退出信号进行了封装,通过框架中的方法去 `app.ListenStop` 获取退出信号; 退出信号通过监听方法调用时传入的 channel 类型来传递,通过一个新的协程 `select` 方法来获取信号,具体代码如下。 ~~~ // 监听退出信号 stopSig := make( chan app.StopSignal, 1) go app.ListenStop(stopSig) // 当应用退出时,会收到一个信号 go func() { select { case <-stopSig: fmt.Println("get stopSign ") } }() ~~~ ### 使用建议 - 不建议在控制器中使用 `AppDefer` 和 `ListenStop` 方法,因为调用 http 服务时每次请求都是一个新的 `goroutine` 每次请求都会新增一个重复的后置操作和监听信号; - `AppDefer` 和 `ExitWaitFunDo` 中的处理时长应当是可预知的,避免因超时原因导致中断正常的处理逻辑。