Create another.go
This commit is contained in:
parent
76f30faf5c
commit
e05e4ea97e
129
src/another/another.go
Normal file
129
src/another/another.go
Normal file
@ -0,0 +1,129 @@
|
||||
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,
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
<-quit
|
||||
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")
|
||||
}
|
||||
|
||||
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))
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user