目录

Go程序如何优雅退出

背景

优雅的退出 Go 程序:关闭数据库连接、关闭 redis 连接、等待协程执行、清理数据等等…

实现

通过监听程序信号 ctrl + c 优雅退出,代码实现如下:

package main

import (
    "log"
    "os"
    "os/signal"
    "syscall"
)

func main() {

    //TODO 执行业务代码

    //监听退出序号
    sigs := make(chan os.Signal, 1)
    done := make(chan bool, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
    go func() {
        sig := <-sigs
        log.Println(sig)
        done <- true
    }()
    log.Println("Server Start Awaiting Signal")
    <-done
     // 执行清理操作
    cleanup()
    log.Println("Exiting")
}

原理

操作系统信号机制

┌───────────────┐       ┌───────────────┐
│  用户按下Ctrl+C │─────>│ 生成SIGINT信号  │
└───────────────┘       └───────────────┘
          ↓
┌───────────────────────────────┐
│ Go程序通过signal.Notify捕获信号 │
└───────────────────────────────┘
信号名称 默认行为 触发场景 Go可否捕获
​SIGINT​ 终止进程 Ctrl+C / kill -2
​SIGTERM​ 终止进程 kill默认 / 容器停止
​SIGKILL​ 强制终止 kill -9 / 系统OOM
​SIGHUP​ 终止进程 终端断开 / 守护进程重载配置
​SIGQUIT​ 核心转储 Ctrl+\

常见问题

1. 为什么有时候捕获不到?

操作系统强制终止进程 / 内存溢出被容器强制终止,不经过应用程序处理流程