os.Signal channel,然后使用 signal.Notify 注册要接收的信号。
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
// signal.Notify(c)
signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println(sig)
done <- true
}()
fmt.Println("wait for signal")
<- done
fmt.Println("got signal and exit")
fmt.Println("run done")
}
如何实现进程的优雅退出
首先什么是优雅退出呢?所谓的优雅退出,其实就是避免暴力杀死进程,让进程在接收到信号之后,自动的做一些善后处理,再自己自愿的退出。
Linux Server端的应用程序经常会长时间运行,在运行过程中,可能申请了很多系统资源,也可能保存了很多状态,在这些场景下,我们希望进程在退出前,可以释放资源或将当前状态dump到磁盘上或打印一些重要的日志,也就是希望进程优雅退出(exit gracefully)。
从上面的介绍不难看出,优雅退出可以通过捕获SIGTERM来实现。具体来讲,通常只需要两步动作:
1)注册SIGTERM信号的处理函数并在处理函数中做一些进程退出的准备。信号处理函数的注册可以通过signal()或sigaction()来实现,其中,推荐使用后者来实现信号响应函数的设置。信号处理函数的逻辑越简单越好,通常的做法是在该函数中设置一个bool型的flag变量以表明进程收到了SIGTERM信号,准备退出。
2)在主进程的main()中,通过类似于while(!bQuit)的逻辑来检测那个flag变量,一旦bQuit在signal handler function中被置为true,则主进程退出while()循环,接下来就是一些释放资源或dump进程当前状态或记录日志的动作,完成这些后,主进程退出。
这个在我前面的一篇文章中也介绍过【=[golang的httpserver优雅重启][1]】//www.jb51.net/article/137069.htm,里面介绍了一般我们使用的httpserver如何做到优雅重启,这里面也介绍了一些信号的使用,和优雅重启的思路。今天这里我们介绍的是如何优雅退出,其实是优雅重启的一个简化版。
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
sigs := make(chan os.Signal, 1)
// done := make(chan bool, 1)
// signal.Notify(sigs)
// signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM)
signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
// go func() {
// sig := <-sigs
// fmt.Println(sig)
// done <- true
// }()
go func() {
for s := range sigs {
switch s {
case syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT:
fmt.Println("got signal and try to exit: ", s)
do_exit()
case syscall.SIGUSR1:
fmt.Println("usr1: ", s)
case syscall.SIGUSR2:
fmt.Println("usr2: ", s)
default:
fmt.Println("other: ", s)
}
}
}()
fmt.Println("wait for signal")
i := 0
for {
i++
fmt.Println("times: ", i)
time.Sleep(1 * time.Second)
}
// <- done
fmt.Println("got signal and exit")
fmt.Println("run done")
}
func do_exit() {
fmt.Println("try do some clear jobs")
fmt.Println("run done")
os.Exit(0)
}









