Race condition with Go http server shutdown

Viewed 202

I'm trying to gracefully shut down HTTP server and want to do some cleanup after the server is shut down(once the server stops accepting new connections). However when I run the program with race enabled, it shows Found 1 data race(s).

package main

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

func serve(ctx context.Context) (err error) {
    mux := http.NewServeMux()
    mux.Handle("/", http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "okay")
        },
    ))

    srv := &http.Server{
        Addr:    ":8000",
        Handler: mux,
    }

    go func() {
        if err = srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen:%+s\n", err)
        }
    }()

    log.Printf("server started")

    <-ctx.Done()

    log.Printf("server stopped")

    ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer func() {
        cancel()
    }()

    if err = srv.Shutdown(ctxShutDown); err != nil {
        log.Fatalf("server Shutdown Failed:%+s", err)
    }

    log.Printf("server exited properly")

    if err == http.ErrServerClosed {
        err = nil
    }

    return
}

func main() {
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)

    ctx, cancel := context.WithCancel(context.Background())

    go func() {
        oscall := <-c
        log.Printf("system call:%+v", oscall)
        cancel()
    }()

    if err := serve(ctx); err != nil {
        log.Printf("failed to serve:+%v\n", err)
    }
}

Steps to reproduce

go build -race main.go && ./main, after the server is started then initiate a SIGINT with CTRL+C

How can I get rid of the race condition in this code?

0 Answers
Related