我正常停止http.ListenAndServe失败

时间:2018-07-29 11:23:32

标签: http go

我是Go语言的新手。

我正在编写一个Web应用程序,我需要服务器等待活动请求发出后再关闭。

我写了一个处理程序,等待5秒钟回答。如果我发出请求并停止服务器(在5秒钟之前),则会收到“无法连接”错误。

有没有一种方法可以停止监听新请求并等待活动请求完成?

这是我的例子

func main() {
    log.Infof("Starting (PID %d)...", os.Getpid())

    stop := make(chan os.Signal, 1)
    signal.Notify(stop, syscall.SIGTERM)
    signal.Notify(stop, syscall.SIGINT)

    listenAt := "127.0.0.1:8000"

    r := newRouter()
    h := &http.Server{Addr: listenAt, Handler: r}

    go func() {
        log.Info("Serving on http://", listenAt)

        if err := h.ListenAndServe(); err != nil {
            log.Fatal(err)
        }
    }()
    <-stop

    log.Info("Stoping ...")
    h.Shutdown(context.Background())
    log.Info("Bye :)")
}

示例处理程序

func handler(w http.ResponseWriter, r *http.Request) {
    time.Sleep(5 * time.Second)
    log.Info("new request")
    fmt.Fprintf(w, "Hola!")
}

完整示例@ https://gist.github.com/nachopro/d80fa71ae49527e1ddcaf359b4ff488b

2 个答案:

答案 0 :(得分:1)

感谢这个blog entry和他们的例子,我找到了这个issue和他们的solution。我看到我的问题与net / http模块无关!

真正的问题是log.Fatal(err)中的go func(),将其更改为log.Info(err)不会中止关机过程。

go func() {
    log.Info("Serving on http://", listenAt)

    if err := h.ListenAndServe(); err != nil {
        // log.Fatal(err)
        log.Info(err)
    }
}()

答案 1 :(得分:0)

一种方法是通过以下方式将最大连接数限制为1:

l, err := net.Listen("tcp", ":8000")

if err != nil {
    log.Fatalf("Listen: %v", err)
}

defer l.Close()

l = netutil.LimitListener(l, 1)

log.Fatal(http.Serve(l, nil))

另一种方法是使用全局变量:

package main

import (
    "net/http"
    "sync/atomic"
    "fmt"
)

var toggle *int32

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
    val := atomic.LoadInt32(toggle)
    if val != 0 {
        fmt.Fprintln(w, "Not Valid!")
        w.WriteHeader(http.StatusForbidden)
        return
    }

    atomic.StoreInt32(toggle, 1)
    // do stuff
    w.WriteHeader(http.StatusOK)
}

func init (){
    atomic.StoreInt32(toggle, int32(0))
}

**请注意,两种方法都适用于单节点服务器,不适用于分布式系统,为此,解决方案是使用Redis等缓存服务器。