doujichan1399
2017-07-22 15:23 浏览 91
已采纳

http.Server ListenAndServer,然后即时关机不起作用

I'm trying to track down an issue in a larger program and wrote this small test program to help resolve it.

If I start a http server and then instantly try to shut it down it doesn't shutdown and continues to serve requests. I can reason about the behavior but can't work out a way around it. I'm assuming it's because the server hasn't fully started up before I try to shut it down and so the shutdown fails and the startup continues and then finishes leaving it to serve requests as normal.

How can I ensure the server is in a state that it can be shutdown before I call shutdown? If you comment out the sleep function between starting and stopping the server you will see it works as desired.

package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "os/signal"
    "time"
)

func main() {
    // stop on ^c
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt)

    // router
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("serving request")
        io.WriteString(w, "Hello, world!
")
    })

    // start server
    srv := &http.Server{Addr: ":8080", Handler: mux}
    go func() {
        if err := srv.ListenAndServe(); err != nil {
            log.Printf("listenAndServe failed: %v", err)
        }
    }()
    fmt.Println("server started")

    // time.Sleep(1 * time.Second)

    // gracefully stop server
    d := time.Now().Add(60 * time.Second)
    ctx, cancel := context.WithDeadline(context.Background(), d)
    defer cancel()
    if err := srv.Shutdown(ctx); err != nil {
        fmt.Println(err)
    }
    fmt.Println("server stopped")

    <-quit
}

Simply run this program and access http://localhost:8080. You will see it will keep serving requests even though we tried to shut it down.

The output of the program should be:

:; go run main.go
server started
server stopped
2017/07/22 16:17:11 serve failed: http: Server closed

instead it is:

:; go run main.go
server started
server stopped
serving request
serving request
serving request
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答 默认 最新

  • 已采纳
    dpiz9879 dpiz9879 2017-07-22 15:43

    Your call to srv.ListenAndServe can be, and apparently is, called after srv.Shutdown. You can verify this by adding a logging statement the goroutine just before the call to srv.ListenAndServe. To see that the shutdown works when called after ListenAndServe, you can uncomment your time.Sleep(1 * time.Second). Here a typical use of Shutdown would be to call it right after your <-quit:

    func main() {
        // stop on ^c
        quit := make(chan os.Signal)
        signal.Notify(quit, os.Interrupt)
    
        // router
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            log.Println("serving request")
            io.WriteString(w, "Hello, world!
    ")
        })
    
        // start server
        srv := &http.Server{Addr: ":8080", Handler: mux}
        go func() {
            log.Println("server starting")
            if err := srv.ListenAndServe(); err != nil {
                log.Fatalf("listenAndServe failed: %v", err)
            }
        }()
        fmt.Println("server started")
    
        <-quit
        // gracefully stop server
        ctx, cancel := context.WithTimeout(context.Background(), 60 * time.Second)
        defer cancel()
        if err := srv.Shutdown(ctx); err != nil {
            log.Fatal(err)
        }
        log.Println("server stopped")
    }
    
    点赞 评论 复制链接分享

相关推荐