【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
}

上一篇下一篇

猜你喜欢

热点阅读