[docs] Add graceful shutdown example (#329)
This commit is contained in:
128
README.md
128
README.md
@@ -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))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user