触发 SIGTERM 时停止 main.go
Stop main.go when SIGTERM triggered
当 SIGTERM 事件被触发时,我无法退出我的 main.go 应用程序。
switch 语句中的 SIGTERM case 没有被调用并且“triggered”没有被打印出来。
这是我的代码
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)
}
我尝试了以下解决方案,但无法正常工作。
- Golang catch signals
因为 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") 未显示的一个常见原因是 go run
执行,因为该进程在子进程中 运行。 Kill go run
只会向它发送信号,子进程将被终止。让我们尝试使用 go build
看看到底发生了什么。
您的代码已接近实现问题中所述的目标。
循环接收信号以处理在 SIGTERM 之前接收到 SIGINT 的情况。如果你想在 SIGTERM 上退出进程,那么这样做:
signalChannel := make(chan os.Signal, 2)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
去功能(){
对于 sig := 范围 signalChanne {
开关信号{
案例os.Interrupt:
//还没有
案例syscall.SIGTERM:
fmt.Printf("triggered\n")
os.Exit(1)
}
}
}()
如果收到 SIGTERM,此程序将打印“已触发”。
当 SIGTERM 事件被触发时,我无法退出我的 main.go 应用程序。
switch 语句中的 SIGTERM case 没有被调用并且“triggered”没有被打印出来。
这是我的代码
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)
}
我尝试了以下解决方案,但无法正常工作。
- Golang catch signals
因为 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") 未显示的一个常见原因是 go run
执行,因为该进程在子进程中 运行。 Kill go run
只会向它发送信号,子进程将被终止。让我们尝试使用 go build
看看到底发生了什么。
您的代码已接近实现问题中所述的目标。 循环接收信号以处理在 SIGTERM 之前接收到 SIGINT 的情况。如果你想在 SIGTERM 上退出进程,那么这样做:
signalChannel := make(chan os.Signal, 2) signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) 去功能(){ 对于 sig := 范围 signalChanne { 开关信号{ 案例os.Interrupt: //还没有 案例syscall.SIGTERM: fmt.Printf("triggered\n") os.Exit(1) } } }()
如果收到 SIGTERM,此程序将打印“已触发”。