Golang 语言中怎么拦截系统信号和优雅退出 http server?

简介: Golang 语言中怎么拦截系统信号和优雅退出 http server?

介绍

系统信号是在类 Unix 系统中用来进程间通讯的一种方式。我们可以使用 kill -l 命令查看各个系统支持的信号列表,每个信号都有名称和编号。我们可以使用 kill 命令给特定进程发送指定信号名称或信号编号的系统信号。

系统信号分为同步信号和异步信号。其中同步信号是程序执行中的错误触发的信号,在 Golang 程序中,同步信号通常会被转换为 runtime panic,异步信号是系统内核或其它程序发送的信号。

关于系统信号的更多内容,感兴趣的读者朋友可以自行检索相关资料学习。本文我们主要介绍怎么使用 Golang 语言拦截系统信号和怎么实现优雅退出 http server。

Golang 标准库 os/signal

关于如何使用 Golang 语言拦截系统信号的问题,Golang 在标准库 os/signal 包中,提供了几个函数,可以拦截系统信号。我们重点介绍 Notify 函数。

func Notify(c chan<- os.Signal, sig ...os.Signal)

os/signal 包的 Notify 函数将输入信号中继到 channel c。如果未指定信号(sig 参数为空),则所有输入信号都将中继到 channel c。否则,将仅拦截指定的信号。

os/signal 包将不会阻塞发送输入信号到 channel c,Notify 函数调用方必须确保 channel c 有足够的缓冲区空间,以跟上预期的信号速率。对于仅用于通知一个信号值的 channel,大小为 1 的缓冲区就足够了。

接收指定信号的示例代码:

func main() {
 // Set up channel on which to send signal notifications.
 // We must use a buffered channel or risk missing the signal
 // if we're not ready to receive when the signal is sent.
 c := make(chan os.Signal, 1)
 signal.Notify(c, os.Interrupt)
 // Block until a signal is received.
 s := <-c
 fmt.Println("Got signal:", s)
}

接收所有信号的示例代码:

package main
import (
 "fmt"
 "os"
 "os/signal"
)
func main() {
 // Set up channel on which to send signal notifications.
 // We must use a buffered channel or risk missing the signal
 // if we're not ready to receive when the signal is sent.
 c := make(chan os.Signal, 1)
 // Passing no signals to Notify means that
 // all signals will be sent to the channel.
 signal.Notify(c)
 // Block until any signal is received.
 s := <-c
 fmt.Println("Got signal:", s)
}

03

拦截系统信号并优雅退出 http server

我们可以使用 os/signal 包的 Notify 函数拦截系统信号,并通过 http.Server 的 Shutdown 方法优雅退出 http server。

func (srv *Server) Shutdown(ctx context.Context) error

在 Golang 1.8 中新增的 Shutdown 方法可以在不中断任何活动连接的情况下正常关闭服务器。Shutdown 的工作方式是先关闭所有打开的监听器,然后关闭所有空闲连接,然后等待所有活跃连接为空闲状态时,关闭服务器。

如果提供的上下文在关闭完成之前已超时,则 Shutdown 返回上下文的错误,否则它将返回从关闭服务器的监听器返回的错误。

调用 Shutdown 时,Serve,ListenAndServe 和 ListenAndServeTLS 立即返回 ErrServerClosed。确保 Shutdown 未返回时,程序没有退出。

需要注意的是,Shutdown 不会尝试关闭也不等待长连接,例如 WebSockets。如果需要,Shutdown 的调用者应单独通知此类长连接,并等待它们关闭。

一旦调用了 Server 的 Shutdown 方法,server 就无法使用了。如果再调用 Serve 的方法将返回 ErrServerClosed。

优雅退出 http server 的示例代码如下:

func main() {
  // 优雅退出
 http.HandleFunc("/", hello)
 server := http.Server{Addr: ":8080"}
 go func() {
  if err := server.ListenAndServe(); err != nil {
   fmt.Println("server start failed")
  }
 }()
 c := make(chan os.Signal, 1)
 signal.Notify(c, os.Interrupt)
 s := <-c
 fmt.Printf("接收信号:%s\n", s)
 ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
 defer cancel()
 if err := server.Shutdown(ctx); err != nil {
  fmt.Println("server shutdown failed")
 }
 fmt.Println("server exit")
}
func hello (w http.ResponseWriter, r *http.Request) {
 time.Sleep(5 * time.Second)
 fmt.Fprintln(w, "Hello Go!")
}

阅读上面这段代码,可以发现我们拦截到系统信号 SIGNINT 后,通过 sleep 模拟程序还未执行结束(比如需要执行一些收尾工作),此时,系统未直接终止该应用进程(直接终止是系统默认处理信号 SIGINT 的方式),而是等待程序执行结束后,系统才终止该应用进程。

04

总结

本文我们主要介绍了 Golang 语言怎么拦截系统信号,和使用 os/signal 包的 Notify 函数,结合 net/http 包中 http.ServerShutdown 方法,实现优雅退出 http server。

推荐阅读:

参考资料:

https://zh.wikipedia.org/wiki/Unix信号

https://golang.org/pkg/os/signal/#Notify 

https://golang.org/pkg/net/http/#Server.Shutdown 


目录
相关文章
|
24天前
|
监控 运维
HTTPS 证书自动化运维:https证书管理系统- 自动化监控
本文介绍如何设置和查看域名或证书监控。步骤1:根据证书状态选择新增域名或证书监控,线上部署推荐域名监控,未部署选择证书监控。步骤2:查询监控记录详情。步骤3:在详情页查看每日定时检测结果或手动测试。
HTTPS 证书自动化运维:https证书管理系统- 自动化监控
|
24天前
|
Linux 持续交付 调度
HTTPS 证书自动化运维:https证书管理系统-自动化部署
本指南介绍如何部署Linux服务器节点。首先复制生成的Linux脚本命令,然后将其粘贴到目标服务器上运行。接着刷新页面查看节点记录,并点击“配置证书”选择证书以自动部署。最后,节点部署完成,后续将自动调度,无需人工干预。
HTTPS 证书自动化运维:https证书管理系统-自动化部署
|
5月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
177 4
Golang语言之管道channel快速入门篇
|
5月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
88 4
Golang语言文件操作快速入门篇
|
5月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
146 3
Golang语言之gRPC程序设计示例
|
24天前
|
运维 监控 数据安全/隐私保护
HTTPS 证书自动化运维:HTTPS 证书管理系统之使用指南
本文详细介绍【灵燕空间HTTPS证书管理系统】(https://www.lingyanspace.com)的配置与使用,涵盖注册账户、邮箱配置及证书自动签发、监控和部署的一体化指南。通过页面顶部菜单的【视频教程】和【图文教程】,帮助用户从注册到实际应用全面掌握系统操作。最新迭代后,泛域名证书已包含根域名,无需额外申请多域名证书。
|
5月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
116 4
|
24天前
|
运维 监控 安全
HTTPS 证书自动化运维:HTTPS 证书管理系统之优势对比
本文详细介绍了一款功能强大的HTTPS证书管理系统,涵盖自动签发、更新、实时监控、部署一体化、自定义加密算法、集中管理和邮箱通知等功能。系统通过简化配置、智能引导、快速响应和多重防护等优势,确保企业和个人用户能高效、安全地管理证书,提升网站和应用的安全性。
|
3月前
|
监控 开发者 Perl
perl use HTTP::Server::Simple 轻量级 http server
使用 **HTTP::Server::Simple** 模块,Perl 开发者可以快速创建和配置一个轻量级的HTTP服务器。通过继承和扩展 `handle_request` 方法,可以实现复杂的请求处理逻辑。结合日志记录功能,可以更好地监控服务器运行情况。无论是用于开发测试还是简单的生产环境应用,这种轻量级解决方案都能提供很好的支持。
78 2
|
3月前
|
网络协议 安全 Go
Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
【10月更文挑战第28天】Go语言进行网络编程可以通过**使用TCP/IP协议栈、并发模型、HTTP协议等**方式
90 13