棋牌游戏项目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 nilcase sig := <-c:switch sig {case syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT:stop()log.Println("user app quit")return nilcase syscall.SIGHUP:stop()log.Println("hang up user app quit")return nildefault:return nil}}}
}
结论
- 将
main.go
代码 select {}
去除后,metric.Serve()
将随 app.Run(context.Background())
结束而结束,因为 app.Run 是 main 唯一的阻塞条件,因此 main 不需要接收信号也能退出 - 之所以会这样考虑,是因为信号被
app.go
处理了,所以 ctrl + c
没有作用于 main.go
中 - 因此
main.go
的 select
会一直阻塞造成无法退出