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 處理程序。
在原始程式碼中,您在伺服器啟動後設定 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
端點,因為它們是在伺服器啟動之前定義的。
http 處理程序在伺服器啟動之前設置,並且日誌語句在伺服器啟動之前列印。這應該可以解決您的問題並允許伺服器按預期啟動和處理請求。另外,現在伺服器知道在哪裡監聽,因為 addr
已明確定義。
以上是Worker 和 HTTP 伺服器正常關閉的詳細內容。更多資訊請關注PHP中文網其他相關文章!