Worker 和 HTTP 服务器正常关闭

Cma*_*mag -3 concurrency go

我正在尝试创建一个独立启动的工作进程和一个 HTTP 服务器,并监听终止并在完成后优雅退出。

由于某种原因,工作程序启动,但 HTTP 服务器没有启动,直到发送 SIGTERM 事件。只有在发送 sigterm 事件后,http 服务器才会启动。下面的问题出在哪里?

输出

https://gosamples.dev is the best
https://gosamples.dev is the best
https://gosamples.dev is the best
^C2023/05/27 15:07:52 Listening on HTTP server port:

Process finished with the exit code 0
Run Code Online (Sandbox Code Playgroud)

代码

https://gosamples.dev is the best
https://gosamples.dev is the best
https://gosamples.dev is the best
^C2023/05/27 15:07:52 Listening on HTTP server port:

Process finished with the exit code 0
Run Code Online (Sandbox Code Playgroud)

Von*_*onC 5

如果我正确地阅读了您的代码,您将在定义路由处理程序之前启动服务器。这意味着当服务器启动时,它不知道您的/readiness/liveness端点,因为您还没有添加它们。结果,服务器启动,但它不执行任何操作,因为它没有要处理的路由。

然后,您不会Addrhttp.Server实例中定义该字段。使用在调用它的实例字段ListenAndServe()中定义的地址。如果它为空,则默认为,但这在您的代码中没有明确说明,这可能会导致混乱。Addrhttp.Server":http"

我移到srv.ListenAndServe了startServer的最后。我错过了什么?

问题不在于srv.ListenAndServe函数中的位置,而在于如何http.Server配置以及何时设置 HTTP 处理程序。

在原始代码中,您在服务器启动后设置 HTTP 处理程序。需要在启动服务器之前设置处理程序,因为一旦服务器运行,它将不会拾取稍后定义的任何新处理程序。

并且日志语句log.Printf("Listening on HTTP server port: %s", srv.Addr)是 after srv.ListenAndServe(),这是一个阻塞调用。这意味着日志语句只会在服务器停止后运行,这就是为什么您只能在发送 SIGTERM 信号后才能看到它。

尝试startServer像这样重新组织你的函数:

func startServer(ctx context.Context) error {
    srv := &http.Server{
        Addr: ":8080", // Define the address where you want the server to listen
    }

    http.HandleFunc("/readiness", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(200)
    })
    http.HandleFunc("/liveness", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(200)
    })

    go func() {
        <-ctx.Done() // Wait for the context to be done

        // Shutdown the server
        if err := srv.Shutdown(context.Background()); err != nil {
            // Error from closing listeners, or context timeout:
            log.Printf("HTTP server Shutdown: %v", err)
        }
    }()

    log.Printf("Listening on HTTP server port: %s", srv.Addr)

    if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        // Error starting or closing listener:
        return fmt.Errorf("HTTP server ListenAndServe: %w", err)
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)

在函数的这个修改版本中startServer,服务器现在知道您的端点/readiness/liveness端点,因为它们是在服务器启动之前定义的。
HTTP 处理程序在服务器启动之前设置,并且日志语句在服务器启动之前打印。这应该可以解决您的问题并允许服务器按预期启动和处理请求。此外,现在服务器知道在哪里监听,正如Addr明确定义的那样。