Skip to content

Instantly share code, notes, and snippets.

@enricofoltran
Last active September 30, 2025 12:29
Show Gist options
  • Save enricofoltran/10b4a980cd07cb02836f70a4ab3e72d7 to your computer and use it in GitHub Desktop.
Save enricofoltran/10b4a980cd07cb02836f70a4ab3e72d7 to your computer and use it in GitHub Desktop.

Revisions

  1. Enrico Foltran revised this gist Jan 7, 2018. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -47,6 +47,7 @@ func main() {
    IdleTimeout: 15 * time.Second,
    }

    done := make(chan bool)
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)

    @@ -55,21 +56,23 @@ func main() {
    logger.Println("Server is shutting down...")
    atomic.StoreInt32(&healthy, 0)

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    logger.Fatalf("Could not gracefully shutdown the server: %v\n", err)
    }
    close(done)
    }()

    logger.Println("Server is ready to handle requests at", listenAddr)
    atomic.StoreInt32(&healthy, 1)
    if err := server.ListenAndServe(); err != http.ErrServerClosed {
    if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
    logger.Fatalf("Could not listen on %s: %v\n", listenAddr, err)
    }

    <-done
    logger.Println("Server stopped")
    }

  2. Enrico Foltran revised this gist Jan 7, 2018. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -52,15 +52,15 @@ func main() {

    go func() {
    <-quit
    logger.Println("Server is shoutting down...")
    logger.Println("Server is shutting down...")
    atomic.StoreInt32(&healthy, 0)

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    logger.Fatalf("Could not gracefully shoutdown the server: %v\n", err)
    logger.Fatalf("Could not gracefully shutdown the server: %v\n", err)
    }
    }()

  3. Enrico Foltran created this gist Jan 7, 2018.
    126 changes: 126 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,126 @@
    package main

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

    type key int

    const (
    requestIDKey key = 0
    )

    var (
    listenAddr string
    healthy int32
    )

    func main() {
    flag.StringVar(&listenAddr, "listen-addr", ":5000", "server listen address")
    flag.Parse()

    logger := log.New(os.Stdout, "http: ", log.LstdFlags)
    logger.Println("Server is starting...")

    router := http.NewServeMux()
    router.Handle("/", index())
    router.Handle("/healthz", healthz())

    nextRequestID := func() string {
    return fmt.Sprintf("%d", time.Now().UnixNano())
    }

    server := &http.Server{
    Addr: listenAddr,
    Handler: tracing(nextRequestID)(logging(logger)(router)),
    ErrorLog: logger,
    ReadTimeout: 5 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout: 15 * time.Second,
    }

    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)

    go func() {
    <-quit
    logger.Println("Server is shoutting down...")
    atomic.StoreInt32(&healthy, 0)

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    logger.Fatalf("Could not gracefully shoutdown the server: %v\n", err)
    }
    }()

    logger.Println("Server is ready to handle requests at", listenAddr)
    atomic.StoreInt32(&healthy, 1)
    if err := server.ListenAndServe(); err != http.ErrServerClosed {
    logger.Fatalf("Could not listen on %s: %v\n", listenAddr, err)
    }

    logger.Println("Server stopped")
    }

    func index() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
    http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
    return
    }
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.Header().Set("X-Content-Type-Options", "nosniff")
    w.WriteHeader(http.StatusOK)
    fmt.Fprintln(w, "Hello, World!")
    })
    }

    func healthz() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if atomic.LoadInt32(&healthy) == 1 {
    w.WriteHeader(http.StatusNoContent)
    return
    }
    w.WriteHeader(http.StatusServiceUnavailable)
    })
    }

    func logging(logger *log.Logger) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    defer func() {
    requestID, ok := r.Context().Value(requestIDKey).(string)
    if !ok {
    requestID = "unknown"
    }
    logger.Println(requestID, r.Method, r.URL.Path, r.RemoteAddr, r.UserAgent())
    }()
    next.ServeHTTP(w, r)
    })
    }
    }

    func tracing(nextRequestID func() string) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    requestID := r.Header.Get("X-Request-Id")
    if requestID == "" {
    requestID = nextRequestID()
    }
    ctx := context.WithValue(r.Context(), requestIDKey, requestID)
    w.Header().Set("X-Request-Id", requestID)
    next.ServeHTTP(w, r.WithContext(ctx))
    })
    }
    }