php小编西瓜在这篇文章中为大家介绍Worker和HTTP服务器的正常关闭。在开发过程中,正确关闭Worker和HTTP服务器是非常重要的,可以确保资源的释放和程序的正常退出。本文将详细讲解如何正确关闭Worker和HTTP服务器,以及一些常见的问题和解决方法。让我们一起来学习如何保证服务器的正常关闭,提高应用程序的稳定性和可靠性。
我正在尝试创建一个独立启动的工作进程和一个 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
package main import ( "context" "fmt" "log" "net/http" "os" "os/signal" "sync" "syscall" "time" ) func main() { ctx, cancel := context.WithCancel(context.Background()) go func() { signals := make(chan os.Signal, 1) signal.Notify(signals, os.Interrupt, syscall.SIGTERM) <-signals cancel() }() var wg sync.WaitGroup wg.Add(1) go func() { if err := myWorker(ctx); err != nil { cancel() } wg.Done() }() wg.Add(1) go func() { if err := startServer(ctx); err != nil { cancel() } wg.Done() }() wg.Wait() } func myWorker(ctx context.Context) error { shouldStop := false go func() { <-ctx.Done() shouldStop = true }() for !shouldStop { fmt.Println("https://gosamples.dev is the best") time.Sleep(1 * time.Second) } return nil } func startServer(ctx context.Context) error { var srv http.Server 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) } }() if err := srv.ListenAndServe(); err != http.ErrServerClosed { // Error starting or closing listener: return fmt.Errorf("HTTP server ListenAndServe: %w", err) } log.Printf("Listening on HTTP server port: %s", srv.Addr) 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) }) return nil }
如果我正确地阅读了您的代码,您将在定义路由处理程序之前启动服务器。这意味着当服务器启动时,它不知道您的 /readiness
和 /liveness
端点,因为您尚未添加它们。结果,服务器启动,但它不执行任何操作,因为它没有要处理的路由。
然后,您不会在 http.server
实例中定义 addr
字段。 listenandserve()
使用调用它的 http.server
实例的 addr
字段中定义的地址。如果为空,则默认为 ":http"
,但这在您的代码中没有明确说明,可能会导致混乱。
我将 srv.listenandserve
移至 startserver 的最末尾。我错过了什么?
问题不在于 srv.listenandserve
在函数中的位置,而在于如何配置 http.server
在函数中的位置,而在于如何配置 http.server
以及何时设置 http 处理程序。
在原始代码中,您在服务器启动后设置 http 处理程序。需要在启动服务器之前设置处理程序,因为一旦服务器运行,它将不会拾取稍后定义的任何新处理程序。
并且日志语句log.printf("listening on http server port: %s", srv.addr)
位于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 }
在 startserver
函数的修改版本中,服务器现在知道您的 /readiness
和 /liveness
函数的修改版本中,服务器现在知道您的
端点,因为它们是在服务器启动之前定义的。addr
http 处理程序在服务器启动之前设置,并且日志语句在服务器启动之前打印。这应该可以解决您的问题并允许服务器按预期启动和处理请求。另外,现在服务器知道在哪里监听,因为
以上是Worker 和 HTTP 服务器正常关闭的详细内容。更多信息请关注PHP中文网其他相关文章!