[docs] Add graceful shutdown example (#329)

This commit is contained in:
Matt Silverlock
2018-01-07 07:57:08 -08:00
committed by GitHub
parent 512169e5d7
commit 5bbbb5b2b5

128
README.md
View File

@@ -27,6 +27,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* [Static Files](#static-files) * [Static Files](#static-files)
* [Registered URLs](#registered-urls) * [Registered URLs](#registered-urls)
* [Walking Routes](#walking-routes) * [Walking Routes](#walking-routes)
* [Graceful Shutdown](#graceful-shutdown)
* [Full Example](#full-example) * [Full Example](#full-example)
--- ---
@@ -45,11 +46,11 @@ Let's start registering a couple of URL paths and handlers:
```go ```go
func main() { func main() {
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/", HomeHandler) r.HandleFunc("/", HomeHandler)
r.HandleFunc("/products", ProductsHandler) r.HandleFunc("/products", ProductsHandler)
r.HandleFunc("/articles", ArticlesHandler) r.HandleFunc("/articles", ArticlesHandler)
http.Handle("/", r) http.Handle("/", r)
} }
``` ```
@@ -68,9 +69,9 @@ The names are used to create a map of route variables which can be retrieved cal
```go ```go
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Category: %v\n", vars["category"]) fmt.Fprintf(w, "Category: %v\n", vars["category"])
} }
``` ```
@@ -122,7 +123,7 @@ r.Queries("key", "value")
```go ```go
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
return r.ProtoMajor == 0 return r.ProtoMajor == 0
}) })
``` ```
@@ -243,24 +244,24 @@ request that matches "/static/*". This makes it easy to serve static files with
```go ```go
func main() { func main() {
var dir string var dir string
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
flag.Parse() flag.Parse()
r := mux.NewRouter() r := mux.NewRouter()
// This will serve files under http://localhost:8000/static/<filename> // This will serve files under http://localhost:8000/static/<filename>
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
srv := &http.Server{ srv := &http.Server{
Handler: r, Handler: r,
Addr: "127.0.0.1:8000", Addr: "127.0.0.1:8000",
// Good practice: enforce timeouts for servers you create! // Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second,
} }
log.Fatal(srv.ListenAndServe()) log.Fatal(srv.ListenAndServe())
} }
``` ```
@@ -383,6 +384,69 @@ r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error
}) })
``` ```
### Graceful Shutdown
Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:
```go
package main
import (
"context"
"flag"
"log"
"net/http"
"os"
"os/signal"
"github.com/gorilla/mux"
)
func main() {
var wait time.Duration
flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m")
flag.Parse()
r := mux.NewRouter()
// Add your routes as needed
srv := &http.Server{
Addr: "0.0.0.0:8080",
// Good practice to set timeouts to avoid Slowloris attacks.
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: r, // Pass our instance of gorilla/mux in.
}
// Run our server in a goroutine so that it doesn't block.
go func() {
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
signal.Notify(c, os.Interrupt)
// Block until we receive our signal.
<-c
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(ctx, wait)
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
log.Println("shutting down")
os.Exit(0)
}
```
## Full Example ## Full Example
Here's a complete, runnable example of a small `mux` based server: Here's a complete, runnable example of a small `mux` based server:
@@ -391,22 +455,22 @@ Here's a complete, runnable example of a small `mux` based server:
package main package main
import ( import (
"net/http" "net/http"
"log" "log"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
func YourHandler(w http.ResponseWriter, r *http.Request) { func YourHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Gorilla!\n")) w.Write([]byte("Gorilla!\n"))
} }
func main() { func main() {
r := mux.NewRouter() r := mux.NewRouter()
// Routes consist of a path and a handler function. // Routes consist of a path and a handler function.
r.HandleFunc("/", YourHandler) r.HandleFunc("/", YourHandler)
// Bind to a port and pass our router in // Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r)) log.Fatal(http.ListenAndServe(":8000", r))
} }
``` ```