首頁  >  文章  >  後端開發  >  Worker 和 HTTP 伺服器正常關閉

Worker 和 HTTP 伺服器正常關閉

WBOY
WBOY轉載
2024-02-15 14:48:071064瀏覽

Worker 和 HTTP 服务器正常关闭

php小編西瓜在這篇文章中為大家介紹Worker和HTTP伺服器的正常關閉。在開發過程中,正確關閉Worker和HTTP伺服器是非常重要的,可以確保資源的釋放和程式的正常退出。本文將詳細說明如何正確關閉Worker和HTTP伺服器,以及一些常見的問題和解決方法。讓我們一起來學習如何確保伺服器的正常關閉,並提高應用程式的穩定性和可靠性。

問題內容

我正在嘗試建立一個獨立啟動的工作進程和一個 http 伺服器,並偵聽終止並在完成後正常退出。

由於某種原因,工作執行緒啟動,但 http 伺服器沒有啟動,直到發送 s​​igterm 事件。只有在發送 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中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除