golang里捕获进程信号实现优雅退出的方法
程序优雅退出可以更好的释放资源,或者打印一些重要的日志信息,在golang里可以实现捕获处理Signal信号来实现进程的优雅退出。
POSIX中定义的信号
POSIX.1-1990标准中定义的信号列表如下:
| 信号 | 值 | 动作 | 说明 |
|---|---|---|---|
| SIGHUP | 1 | Term | 终端控制进程结束(终端连接断开) |
| SIGINT | 2 | Term | 用户发送INTR字符(Ctrl+C)触发 |
| SIGQUIT | 3 | Core | 用户发送QUIT字符(Ctrl+/)触发 |
| SIGILL | 4 | Core | 非法指令(程序错误、试图执行数据段、栈溢出等) |
| SIGABRT | 6 | Core | 调用abort函数触发 |
| SIGFPE | 8 | Core | 算术运行错误(浮点运算错误、除数为零等) |
| SIGKILL | 9 | Term | 无条件结束程序(不能被捕获、阻塞或忽略) |
| SIGSEGV | 11 | Core | 无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作) |
| SIGPIPE | 13 | Term | 消息管道损坏(FIFO/Socket通信时,管道未打开而进行写操作) |
| SIGALRM | 14 | Term | 时钟定时信号 |
| SIGTERM | 15 | Term | 结束程序(可以被捕获、阻塞或忽略) |
| SIGUSR1 | 30,10,16 | Term | 用户保留 |
| SIGUSR2 | 31,12,17 | Term | 用户保留 |
| SIGCHLD | 20,17,18 | Ign | 子进程结束(由父进程接收) |
| SIGCONT | 19,18,25 | Cont | 继续执行已经停止的进程(不能被阻塞) |
| SIGSTOP | 17,19,23 | Stop | 停止进程(不能被捕获、阻塞或忽略) |
| SIGTSTP | 18,20,24 | Stop | 停止进程(可以被捕获、阻塞或忽略) |
| SIGTTIN | 21,21,26 | Stop | 后台程序从终端中读取数据时触发 |
| SIGTTOU | 22,22,27 | Stop | 后台程序向终端中写数据时触发 |
golang里捕获Signal信号
Golang里使用signal.Notify可以接收的指定的信号,会用到os/signal包,具体实现代码为:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func listenSignal() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1,
syscall.SIGUSR2, syscall.SIGTSTP)
select {
case <-sigs:
fmt.Println("exitapp,sigs:", sigs)
os.Exit(0)
}
}
func main() {
fmt.Println("start...")
go listenSignal()
sum := 0
for {
sum++
fmt.Println(sum)
time.Sleep(time.Second)
}
}运行后按Ctrl+C或者调试环境下退出,均可以打印出"exitapp,sigs:xxx"。
docker里优雅退出golang程序
如果在docker关闭的时候要优雅的退出自己的程序,则在docker里程序的pid要为1才可以捕获到进程退出信号,我的做法是将自己的程序作为启动命令来启动。