go实现程序的优雅退出思路详解

292 阅读1分钟

首先,何为优雅退出?

我们最常见的杀死一个应用程序是通过kill -9 或者在应用程序上执行ctrl+c。

但是程序内部如何结束的我们不得而知, 如果是暴力立刻中断,显然不是我们想要的优雅退出。

说到这,我们就大致清楚了优雅退出需要考虑哪些问题。

  1. 收到停止请求时,当前正在处理的任务如何处理? 让其正常执行完毕后再优雅退出。
  2. 收到请求时,后来的任务和请求如何处理? 不处理这些请求任务,等待1中的请求任务处理完毕后退出程序。

下面用一个流程图来说明此问题。

image.png

这里主要涉及到2个信号的传递

  1. 程序接受到终止信号后,告知任务程序停止接受新的请求任务。
  2. 任务程序运行完毕后,告知主程序优雅退出。

下面通过代码来进行演示

package main

import "fmt"
import "os"
import "time"
import "syscall"
import "os/signal"

var (
    stop       = false
    finish     = make(chan bool)
    quitSignal = make(chan os.Signal)
)

func main() {
    signal.Notify(quitSignal, []os.Signal{syscall.SIGINT, syscall.SIGTERM}...)

    go start()

    // 收到终止信号后, shutdown
    <-quitSignal
    close(quitSignal)

    shutdown()
    fmt.Println("stop")

    <-finish
    close(finish)
    fmt.Println("exit")
}

func start() {
    fmt.Println("start")
    // 如果收到终止信号,则停止执行任务
    for !stop {
       fmt.Println("do")
       time.Sleep(time.Second)
    }

    // 任务执行完毕后,通知主协程退出程序
    finish <- true
}

func shutdown() {
    stop = true
}