【Go】优雅上下线(一)
2022-04-19 本文已影响0人
如雨随行2020
@[toc]
说明
当你有一个运行在服务器上的程序需要停止时,因为要保持数据的一致性,不能直接杀死程序(kill -9),而是需要做一些“善后”处理,一般来说就是把当前处理的任务完成,这往往涉及多个协程之间协作(后续会展开)。
那应该怎么处理这种情况呢?我们注意到,在关闭程序(并非kill9强制杀死程序)时,Go可以收到Unix信号,一般来说是两个syscall.SIGINT, syscall.SIGTERM
,pm2发送SIGINT(2),k8s发送SIGTERM(15)。
依据这个,我们可以在程序开始的时候加个监控协程,监听Unix信号,维护一个通道,当收到关闭信号时,将通道关闭,子协程就可以根据通道状态来做到处理完当前任务退出,而不是继续处理下一个
代码
// 监听关闭信号(pm2发送SIGINT,k8s发送SIGTERM),然后关闭stop协程
// 程序可以调用Closed来获取stop的状态
// 也可以通过GetStopChan来拿到stop,自己监听
// Once.Do保证MonitorStop只会被调用一次
var stop = make(chan struct{}) //优雅关闭程序标志
var once = sync.Once{}
func MonitorStop() {
once.Do(func() {
// 收到pm2或者k8s的Signal后,设置stop为true,处理完当前的历史课堂后,程序结束
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
sig := <-signals
fmt.Printf("process will stop gracefully for sig[%d]\n", sig)
close(stop)
})
}
func Closed() bool {
select {
case <-stop:
return true
default:
return false
}
}
func GetStopChan() <-chan struct{} {
return stop
}