Go语言 worker和http服务器正常关闭

92dk7w1h  于 2023-06-03  发布在  Go
关注(0)|答案(1)|浏览(164)

bounty将在5天内到期。回答此问题可获得+100声望奖励。Cmag希望吸引更多的注意力这个问题:寻找一个工作的解决方案乡亲!希望同时启动工作例程和服务器例程。

谢谢你
我正在尝试创建一个独立启动的工人和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
}
whitzsjs

whitzsjs1#

如果我没有看错代码,您可以在定义路由处理程序之前启动服务器。这意味着当服务器启动时,它不知道您的/readiness/liveness端点,因为您尚未添加它们。结果,服务器启动,但它不做任何事情,因为它没有要处理的路由。
然后,您就不用在http.Server示例中定义Addr字段。ListenAndServe()使用在其被调用的http.Server示例的Addr字段中定义的地址。如果它为空,则默认为":http",但这在代码中没有显式说明,这可能会导致混淆。
我把srv.ListenAndServe移到了startServer的最后。我错过了什么?
问题不在于srv.ListenAndServe在函数中的位置,而在于如何配置http.Server以及何时设置HTTP处理程序。
在原始代码中,您将在服务器启动后设置HTTP处理程序。在启动服务器之前需要设置处理程序,因为一旦服务器运行,它将不会拾取任何稍后定义的新处理程序。
log语句log.Printf("Listening on HTTP server port: %s", srv.Addr)srv.ListenAndServe()之后,这是一个阻塞调用。这意味着log语句将只在服务器停止后运行,这就是为什么您只在发送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是显式定义的。

相关问题