写了一段时间的golang后台,怎么优雅的退出程序一直是一个很模糊的问题。思路还是之前的思路,各种标志和变量来回控制,虽然说是能够满足需求,但是总感觉那打开的姿势不对,下面对优雅的退出golang做一个小总结,废话不多说,直接上代码。
1.代码
主程序代码。模拟一个服务对象,函数Reload
和Close
分别是重载和退出,通过打印显示调用。
1.1 模拟的服务service
实现
type service struct {
}
func New() *service {
return nil
}
func (s *service) Close() error {
fmt.Println("srv close ")
return nil
}
func (s *service) Reload() error {
fmt.Println("srv reload ")
return nil
}
1.2 监听信号的工具函数
// HandlerExit handler exit signal
func HandlerExit(exitFn func(s os.Signal) int) {
sch := make(chan os.Signal, 1)
signal.Notify(sch, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
s := <-sch
os.Exit(exitFn(s))
}
// HandlerReload handler Reload signal
func HandlerReload(reload func(s os.Signal)) {
go func() {
sch := make(chan os.Signal, 1)
signal.Notify(sch, syscall.SIGHUP)
for s := range sch {
reload(s)
}
}()
}
1.3 main调用部分
srv := New()
logger.Printf("++++已经启动++++")
utils.HandlerReload(func(s os.Signal) {
logger.Printf("receive signal %s", s)
if err := srv.Reload(); err != nil {
logger.Printf("reload config error: %s", err)
}
})
utils.HandlerExit(func(s os.Signal) int {
logger.Printf("receive get a signal %s", s.String())
if err := srv.Close(); err != nil {
logger.Printf(" service exit, error: %s", err)
return 1
}
logger.Printf(" service exit")
return 0
})
以上就已经实现了通过检测信号使go程序正常退出。需要指出的是这里的正常退出只是最一开始的部分,程序内部的逻辑需要使用到别的都一些知识点来协作,完成go程序的正常退出。在golang学习笔记-优雅的退出golang服务2详细说明。
2.运行结果
程序编译启动后,查到进程的pid,向进程发送SIGNUP
信号,程序收到这个信号后,执行Reload
函数,打印重启的日志。退出时发送kill或者quit信号都可以检测到,结果如下:
3. 小结
3.1 常见的信号
不同平台的信号定义或许有些不同。下面列出了POSIX中定义的信号。
Linux 使用34-64信号用作实时系统中。
命令 man signal 提供了官方的信号介绍。
在POSIX.1-1990标准中定义的信号列表