我正在尝试创建一个独立启动的工作进程和一个 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)
如果我正确地阅读了您的代码,您将在定义路由处理程序之前启动服务器。这意味着当服务器启动时,它不知道您的/readiness
和/liveness
端点,因为您还没有添加它们。结果,服务器启动,但它不执行任何操作,因为它没有要处理的路由。
然后,您不会Addr
在http.Server
实例中定义该字段。使用在调用它的实例字段ListenAndServe()
中定义的地址。如果它为空,则默认为,但这在您的代码中没有明确说明,这可能会导致混乱。Addr
http.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
明确定义的那样。