棋牌游戏项目ctrl + c无法退出进程问题
cd user && go run main.go
启动之前先加入调试语句 在 go func() { metric.Serve(...) }
打日志 在 app.Run(...)
打日志 user/main.go
var configFile = flag. String ( "config" , "application.yaml" , "config file" ) func main ( ) { flag. Parse ( ) config. InitConfig ( configFile) log. Println ( "metric serve" ) go func ( ) { metric. Serve ( fmt. Sprintf ( "0.0.0.0:%d" , config. Conf. MetricPort) ) } ( ) log. Println ( "start app" ) err := app. Run ( context. Background ( ) ) if err != nil { panic ( "run app error\n" ) } select { }
}
启动之后的终端输出如下 但是当输入 ctrl + c
时,退出失败 程序会输出 user/app.go
的调试日志信息 调试信息来自 user/app.go
, 来看看里面的逻辑
func Run ( ctx context. Context) error { server := grpc. NewServer ( ) go func ( ) { listen, err := net. Listen ( "tcp" , config. Conf. Grpc. Addr) if err != nil { log. Fatalf ( "Failed to listen on %s: %v" , config. Conf. Grpc. Addr, err) } if err := server. Serve ( listen) ; err != nil { log. Fatalf ( "Failed to serve: %v" , err) } } ( ) c := make ( chan os. Signal, 1 ) signal. Notify ( c, syscall. SIGTERM, syscall. SIGQUIT, syscall. SIGINT, syscall. SIGHUP, ) stop := func ( ) { server. Stop ( ) fmt. Println ( "stop app finish" ) } for { select { case <- ctx. Done ( ) : return nil case sig := <- c: switch sig { case syscall. SIGTERM, syscall. SIGQUIT, syscall. SIGINT: stop ( ) log. Println ( "user app quit" ) return nil case syscall. SIGHUP: stop ( ) log. Println ( "hang up user app quit" ) return nil default : return nil } } }
}
结论
将 main.go
代码 select {}
去除后,metric.Serve()
将随 app.Run(context.Background())
结束而结束,因为 app.Run 是 main 唯一的阻塞条件,因此 main 不需要接收信号也能退出 之所以会这样考虑,是因为信号被 app.go
处理了,所以 ctrl + c
没有作用于 main.go
中 因此 main.go
的 select
会一直阻塞造成无法退出