Last active
September 30, 2025 12:29
-
Star
(1,076)
You must be signed in to star a gist -
Fork
(177)
You must be signed in to fork a gist
-
-
Save enricofoltran/10b4a980cd07cb02836f70a4ab3e72d7 to your computer and use it in GitHub Desktop.
Revisions
-
Enrico Foltran revised this gist
Jan 7, 2018 . 1 changed file with 5 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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(), 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 != nil && err != http.ErrServerClosed { logger.Fatalf("Could not listen on %s: %v\n", listenAddr, err) } <-done logger.Println("Server stopped") } -
Enrico Foltran revised this gist
Jan 7, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -52,15 +52,15 @@ func main() { go func() { <-quit 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 shutdown the server: %v\n", err) } }() -
Enrico Foltran created this gist
Jan 7, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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)) }) } }