我有一个 gRPC 服务器,我已经实现了像这样正常关闭我的 gRPC 服务器
fun main() {
//Some code
term := make(chan os.Signal)
go func() {
if err := grpcServer.Serve(lis); err != nil {
term <- syscall.SIGINT
}
}()
signal.Notify(term, syscall.SIGTERM, syscall.SIGINT)
<-term
server.GracefulStop()
closeDbConnections()
}
这很好用。
相反,如果我在主 goroutine 中编写 grpcServer.Serve()
逻辑并将关闭处理程序逻辑放入另一个 goroutine,则 server.GracefulStop()
之后的语句通常不会执行.如果完全执行 closeDbConnections()
,一些 DbConnections 将关闭。
server.GracefulStop()
是一个阻塞调用。绝对 grpcServer.Serve()
在 server.GracefulStop()
完成之前完成。那么,这个调用返回后,main goroutine 需要多长时间才能停止?
有问题的代码
func main() {
term := make(chan os.Signal)
go func() {
signal.Notify(term, syscall.SIGTERM, syscall.SIGINT)
<-term
server.GracefulStop()
closeDbConnections()
}()
if err := grpcServer.Serve(lis); err != nil {
term <- syscall.SIGINT
}
}
这个案例没有按预期工作。 server.GracefulStop()
完成后,closeDbConnections()
可能运行也可能不运行(通常不会运行完成)。我通过从我的终端按 Ctrl-C 发送 SIGINT 来测试后一种情况。
有人可以解释一下这种行为吗?
最佳答案
我不确定你的问题(请澄清),但我建议你以这种方式重构你的main
:
func main() {
// ...
errChan := make(chan error)
stopChan := make(chan os.Signal)
// bind OS events to the signal channel
signal.Notify(stopChan, syscall.SIGTERM, syscall.SIGINT)
// run blocking call in a separate goroutine, report errors via channel
go func() {
if err := grpcServer.Serve(lis); err != nil {
errChan <- err
}
}()
// terminate your environment gracefully before leaving main function
defer func() {
server.GracefulStop()
closeDbConnections()
}()
// block until either OS signal, or server fatal error
select {
case err := <-errChan:
log.Printf("Fatal error: %v\n", err)
case <-stopChan:
}
我不认为混合系统事件和服务器错误是个好主意,就像您在示例中所做的那样:如果 Serve
失败,您只需忽略错误并发出系统事件,实际上并没有发生。当导致进程终止的两种不同类型的事件有两种传输( channel )时,请尝试另一种方法。
关于go - golang 中 server.GracefulStop() 的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55797865/