捕获SIGINT和SIGTERM时,Go进程过早死亡

时间:2017-09-13 17:16:27

标签: go signals

我有一个相当直接的信号处理和清理过程:

func signalHandler(shutdown func() error) {
    // Make signal channel and register notifiers for Interupt and Terminate
    sigchan := make(chan os.Signal, 1)
    signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM)

    // Block until we receive a signal on the channel
    <-sigchan

    // Shutdown now that we've received the signal
    if err := shutdown(); err != nil {
        msg := fmt.Sprintf("shutdown error: %s", err.Error())
        log.Fatal(msg)
    }

    log.Println("shutdown procedure complete") 

    // Make a clean exit
    os.Exit(0)
}

这个程序正在从服务器运行一个例行程序:

func (s *Server) Run() error {
    go signalHandler(s.Shutdown) 
    ...

    <-s.done // block until done 
    log.Println("done running!") 
    return nil 
}

func (s *Server) Shutdown() error {
    s.done <- true 
    log.Println("all done here!") 
    return nil 
}

问题是该过程在“所有完成此处!”之前退出。可以打印到日志,有时“完成运行”打印,有时则不打印。好像在其他地方有一个os.Exit()调用(可能在我正在使用的一个库中?)。我确实需要清理连接并删除临时文件等,并且它们没有得到正确的清理。

有谁知道我如何诊断流程退出的位置?

更新:我还没有看到添加该日志语句的“关闭过程完成”。看来该过程在此功能结束之前终止。

1 个答案:

答案 0 :(得分:2)

问题是对Run()的调用是main()中的最后一个真实操作。只要Run()返回,main()返回,当main()返回时,程序退出。我通常将信号处理放在main()本身而不是任何goroutine中,以确保在我处理信号后关闭程序之前main()没有返回。

(根据评论,现在将其作为答案重新排序。)