go - 当 SIGTERM 触发时停止 main.go
问题描述
触发 SIGTERM 事件时,我无法退出我的 main.go 应用程序。
switch 语句中的 SIGTERM 情况不会被调用,并且“触发”不会被打印出来。
这是我的代码
func main() {
port := os.Getenv("PORT")
fmt.Printf("Started\n")
if port == "" {
port = "8080"
}
signalChannel := make(chan os.Signal, 2)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-signalChannel
switch sig {
case os.Interrupt:
//nothing yet
case syscall.SIGTERM:
fmt.Printf("triggered") //never gets called
}
}()
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":" + port, nil)
}
我尝试了以下解决方案,但无法正常工作。
解决方案
因为在http.ListenAndServe()
主 goroutine 上运行。它将锁定为 http 服务器提供服务的进程。
因此,无论您在另一个 goroutine 中做什么,它都不会生效,除非您可以尝试杀死该服务器。为此,您必须获取对要调用的服务器的引用server.Shutdown()
。
正如指出此声明,我相信您正试图通过捕获系统事件来优雅地关闭。虽然类似os.Exit()
或panic
可以完成这项工作,但在 http.Server 运行时这是一个不好的做法。最好保留对正在运行的服务器的引用以server.Shutdown()
使用上下文调用。
随着电流的临近,试试这个方法:
func main() {
port := os.Getenv("PORT")
fmt.Printf("Started\n")
if port == "" {
port = "8080"
}
go func() {
http.HandleFunc("/", HelloServer)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}()
signalChannel := make(chan os.Signal, 2)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
for {
sig := <-signalChannel
switch sig {
case os.Interrupt:
fmt.Println("sigint")
case syscall.SIGTERM:
fmt.Println("sigterm")
return
}
}
}
更新: 我不确定为什么反对投票作为问题想要准确地抓住 SIGTERM,而不是通过 Ctrl+C (SIGINT)
fmt.Println("sigterm") 未显示的一个常见原因是执行 by go run
,因为该进程正在子进程中运行。Killgo run
只会向它发送信号,并且子进程将被终止。让我们试着go build
看看到底发生了什么。
推荐阅读
- javascript - 浏览器下载 .csv 文件而不是在新窗口中打开内容
- r - 求解 R 中的未知值
- c# - 控制器不接收来自 json 的数据
- python - 如何删除文本文件中的某些字符并在 python 中在它们之间创建一条线
- java - 我被困在使用 selenium java 做 UI 对齐问题
- sql-server - TLS 1.2 SQL Server 和 Delphi 客户端
- sql - PostgreSQL 选择最常见的两列组合
- r - 如何创建一个依赖于多列值的虚拟变量?
- c++ - C++ 新手无法弄清楚我哪里出错了。预期的不合格 ID:23
- docker - Docker 坏网关中的 InfluxDB