如何停止Golang中的http.ListenAndServe gRPCEndpoint

如何停止Golang中的http.ListenAndServe gRPCEndpoint 你好,我遇到了一个问题,不知道如何通过 os.Interrupt 信号来正确停止 gRPC 的代理服务器。我自己是这样停止服务器的:

c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)

go func() {
	<-c

	log.Printf("Stopping the Result-Server %s:%d", conf.Host, conf.Port)
	serv.GracefulStop()
	lis.Close()

	close(c)
}()

但我不知道如何对 gRPC 的 HTTP 代理做同样的事情,请告诉我该怎么做?我在这里不能使用 Shutdown(context.TODO())

func NewHTTPServerStart(conf config.GRPCConfig, httpConf config.HTTPConfig) error {
mux := runtime.NewServeMux()

opts := []grpc.DialOption{grpc.WithInsecure()}

gRPCEndpoint := fmt.Sprintf("%s:%d", conf.Host, conf.Port)

err := pb.RegisterResultServiceHandlerFromEndpoint(context.Background(), mux, gRPCEndpoint, opts)
if err != nil {
	return err
}

log.Printf("HTTP Proxy-server started on: %s:%d", httpConf.Host, httpConf.Port)
   //这里是我在收到 Interrupt 信号时如何完成它
return http.ListenAndServe(fmt.Sprintf("%s:%d", httpConf.Host, httpConf.Port), mux)
}

更多代码在 https://github.com/8n0kkw1n/testcmd/pull/1/files


更多关于如何停止Golang中的http.ListenAndServe gRPCEndpoint的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

使用 close net.Listener,示例:

非常感谢,你帮了我大忙

更多关于如何停止Golang中的http.ListenAndServe gRPCEndpoint的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


n0kk:

ListenAndServe

使用 close net.Listener,示例:

// listen
ln, err := net.Listen("tcp","...")
... if err

go func() {
    // accept signal
    ln.Close()
}()
// start server
http.Serve(ln, mux)

要停止 http.ListenAndServe 启动的 gRPC HTTP 代理服务器,你需要创建一个可关闭的 http.Server 实例,并在收到中断信号时调用其 Shutdown 方法。以下是修改后的代码示例:

func NewHTTPServerStart(conf config.GRPCConfig, httpConf config.HTTPConfig) error {
    mux := runtime.NewServeMux()
    
    opts := []grpc.DialOption{grpc.WithInsecure()}
    gRPCEndpoint := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
    
    err := pb.RegisterResultServiceHandlerFromEndpoint(context.Background(), mux, gRPCEndpoint, opts)
    if err != nil {
        return err
    }
    
    server := &http.Server{
        Addr:    fmt.Sprintf("%s:%d", httpConf.Host, httpConf.Port),
        Handler: mux,
    }
    
    // 创建信号通道
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)
    
    // 启动服务器
    go func() {
        log.Printf("HTTP Proxy-server started on: %s:%d", httpConf.Host, httpConf.Port)
        if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("HTTP server error: %v", err)
        }
    }()
    
    // 等待中断信号
    <-stop
    log.Printf("Stopping HTTP Proxy-server %s:%d", httpConf.Host, httpConf.Port)
    
    // 优雅关闭服务器
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    if err := server.Shutdown(ctx); err != nil {
        log.Printf("HTTP server shutdown error: %v", err)
    }
    
    return nil
}

对于你的主函数,可以这样整合两个服务器的关闭:

func main() {
    // 初始化配置...
    
    // 启动 gRPC 服务器
    serv := grpc.NewServer()
    pb.RegisterResultServiceServer(serv, &resultServer{})
    
    lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", conf.Host, conf.Port))
    if err != nil {
        log.Fatal(err)
    }
    
    // 启动 HTTP 代理服务器
    go func() {
        if err := NewHTTPServerStart(conf, httpConf); err != nil {
            log.Fatal(err)
        }
    }()
    
    // 启动 gRPC 服务器
    go func() {
        log.Printf("gRPC server started on: %s:%d", conf.Host, conf.Port)
        if err := serv.Serve(lis); err != nil {
            log.Fatal(err)
        }
    }()
    
    // 等待中断信号
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)
    <-c
    
    log.Printf("Stopping servers...")
    
    // 先关闭 HTTP 代理服务器
    // 这里需要传递 server 实例,可以将其作为返回值或全局变量
    
    // 然后关闭 gRPC 服务器
    serv.GracefulStop()
    lis.Close()
}

这样,当收到 os.Interrupt 信号时,HTTP 代理服务器会通过 Shutdown 方法优雅关闭,而 gRPC 服务器会通过 GracefulStop 方法关闭。两个服务器都会处理完当前请求后再停止。

回到顶部