-
-
Save maisnamraju/34a88f307105b01b43324b61b74e15fa to your computer and use it in GitHub Desktop.
Revisions
-
creack revised this gist
Jan 7, 2018 . 1 changed file with 62 additions and 29 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 @@ -13,20 +13,47 @@ import ( "time" ) type middleware func(http.Handler) http.Handler type middlewares []middleware func (mws middlewares) apply(hdlr http.Handler) http.Handler { if len(mws) == 0 { return hdlr } return mws[1:].apply(mws[0](hdlr)) } func (c *controller) shutdown(ctx context.Context, server *http.Server) context.Context { ctx, done := context.WithCancel(ctx) quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) go func() { defer done() <-quit signal.Stop(quit) close(quit) atomic.StoreInt64(&c.healthy, 0) server.ErrorLog.Printf("Server is shutting down...\n") ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() server.SetKeepAlivesEnabled(false) if err := server.Shutdown(ctx); err != nil { server.ErrorLog.Fatalf("Could not gracefully shutdown the server: %s\n", err) } }() return ctx } type controller struct { logger *log.Logger nextRequestID func() string healthy int64 } func main() { @@ -38,69 +65,75 @@ func main() { logger := log.New(os.Stdout, "http: ", log.LstdFlags) logger.Printf("Server is starting...") c := &controller{logger: logger, nextRequestID: func() string { return strconv.FormatInt(time.Now().UnixNano(), 36) }} router := http.NewServeMux() router.HandleFunc("/", c.index) router.HandleFunc("/healthz", c.healthz) server := &http.Server{ Addr: listenAddr, Handler: (middlewares{c.tracing, c.logging}).apply(router), ErrorLog: logger, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 15 * time.Second, } ctx := c.shutdown(context.Background(), server) logger.Printf("Server is ready to handle requests at %q\n", listenAddr) atomic.StoreInt64(&c.healthy, time.Now().UnixNano()) if err := server.ListenAndServe(); err != http.ErrServerClosed { logger.Fatalf("Could not listen on %q: %s\n", listenAddr, err) } <-ctx.Done() logger.Printf("Server stopped\n") } func (c *controller) index(w http.ResponseWriter, req *http.Request) { if req.URL.Path != "/" { http.NotFound(w, req) return } fmt.Fprintf(w, "Hello, World!\n") } func (c *controller) healthz(w http.ResponseWriter, req *http.Request) { if h := atomic.LoadInt64(&c.healthy); h == 0 { w.WriteHeader(http.StatusServiceUnavailable) } else { fmt.Fprintf(w, "uptime: %s\n", time.Since(time.Unix(0, h))) } } func (c *controller) logging(hdlr http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { defer func(start time.Time) { requestID := w.Header().Get("X-Request-Id") if requestID == "" { requestID = "unknown" } c.logger.Println(requestID, req.Method, req.URL.Path, req.RemoteAddr, req.UserAgent(), time.Since(start)) }(time.Now()) hdlr.ServeHTTP(w, req) }) } func (c *controller) tracing(hdlr http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestID := req.Header.Get("X-Request-Id") if requestID == "" { requestID = c.nextRequestID() } w.Header().Set("X-Request-Id", requestID) hdlr.ServeHTTP(w, req) }) } // main_test.go var ( _ http.Handler = http.HandlerFunc((&controller{}).index) _ http.Handler = http.HandlerFunc((&controller{}).healthz) _ middleware = (&controller{}).logging _ middleware = (&controller{}).tracing ) -
creack revised this gist
Jan 7, 2018 . 1 changed file with 60 additions and 80 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 @@ -2,125 +2,105 @@ package main import ( "context" "fmt" "log" "net/http" "os" "os/signal" "strconv" "sync/atomic" "syscall" "time" ) var healthy int64 func shutdown(quit <-chan os.Signal, server *http.Server) { <-quit server.ErrorLog.Printf("Server is shutting down...\n") atomic.StoreInt64(&healthy, 0) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() server.SetKeepAlivesEnabled(false) if err := server.Shutdown(ctx); err != nil { server.ErrorLog.Fatalf("Could not gracefully shutdown the server: %s\n", err) } } func main() { listenAddr := ":5000" if len(os.Args) == 2 { listenAddr = os.Args[1] } logger := log.New(os.Stdout, "http: ", log.LstdFlags) logger.Printf("Server is starting...") router := http.NewServeMux() router.HandleFunc("/", index) router.HandleFunc("/healthz", healthz) server := &http.Server{ Addr: listenAddr, Handler: tracing(logging(router, logger), func() string { return strconv.FormatInt(time.Now().UnixNano(), 36) }), ErrorLog: logger, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 15 * time.Second, } quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) go shutdown(quit, server) logger.Printf("Server is ready to handle requests at %q\n", listenAddr) atomic.StoreInt64(&healthy, time.Now().UnixNano()) if err := server.ListenAndServe(); err != http.ErrServerClosed { logger.Fatalf("Could not listen on %q: %s\n", listenAddr, err) } logger.Printf("Server stopped\n") } func index(w http.ResponseWriter, req *http.Request) { if req.URL.Path != "/" { http.NotFound(w, req) return } fmt.Fprintf(w, "Hello, World!\n") } func healthz(w http.ResponseWriter, req *http.Request) { h := atomic.LoadInt64(&healthy) if h == 0 { w.WriteHeader(http.StatusServiceUnavailable) return } fmt.Fprintf(w, "uptime: %s\n", time.Since(time.Unix(0, h))) } func logging(hdlr http.Handler, logger *log.Logger) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { defer func(start time.Time) { requestID := w.Header().Get("X-Request-Id") if requestID == "" { requestID = "unknown" } logger.Println(requestID, req.Method, req.URL.Path, req.RemoteAddr, req.UserAgent(), time.Since(start)) }(time.Now()) hdlr.ServeHTTP(w, req) }) } func tracing(hdlr http.Handler, nextRequestID func() string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestID := req.Header.Get("X-Request-Id") if requestID == "" { requestID = nextRequestID() } w.Header().Set("X-Request-Id", requestID) hdlr.ServeHTTP(w, req) }) } -
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)) }) } }