我正常停止http.ListenAndServe失败

I'm a novice Go programmer.

I am writing a web application and I need the server to wait until the active requests are made before closing.

I wrote a handler that waits 5 seconds to answer. If I make a request and stop the server (before the 5 seconds) I get an "Unable to connect" error.

There is a way to stop listen new requests and wait to active requests get done?

Here my example

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 :)")
}

Example Handler

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

Full example @ https://gist.github.com/nachopro/d80fa71ae49527e1ddcaf359b4ff488b

one way is to narrow down your max connection to 1 by:

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))

another way is using a global variable:

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))
}

**notice both ways works for single node servers and does not work in distributed systems, solution for that is using cache servers like redis etc.

Thanks to this blog entry and their example I found this issue and their solution. I saw that my problem isn't related to net/http module!

The real problem is the log.Fatal(err) inside go func(), changing it to log.Info(err) does not abort the shutdown process.

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

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