Skip to content

Commit 5bbbb5b

Browse files
authored
[docs] Add graceful shutdown example (#329)
1 parent 512169e commit 5bbbb5b

File tree

1 file changed

+96
-32
lines changed

1 file changed

+96
-32
lines changed

README.md

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
2727
* [Static Files](#static-files)
2828
* [Registered URLs](#registered-urls)
2929
* [Walking Routes](#walking-routes)
30+
* [Graceful Shutdown](#graceful-shutdown)
3031
* [Full Example](#full-example)
3132

3233
---
@@ -45,11 +46,11 @@ Let's start registering a couple of URL paths and handlers:
4546

4647
```go
4748
func main() {
48-
r := mux.NewRouter()
49-
r.HandleFunc("/", HomeHandler)
50-
r.HandleFunc("/products", ProductsHandler)
51-
r.HandleFunc("/articles", ArticlesHandler)
52-
http.Handle("/", r)
49+
r := mux.NewRouter()
50+
r.HandleFunc("/", HomeHandler)
51+
r.HandleFunc("/products", ProductsHandler)
52+
r.HandleFunc("/articles", ArticlesHandler)
53+
http.Handle("/", r)
5354
}
5455
```
5556

@@ -68,9 +69,9 @@ The names are used to create a map of route variables which can be retrieved cal
6869

6970
```go
7071
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
71-
vars := mux.Vars(r)
72-
w.WriteHeader(http.StatusOK)
73-
fmt.Fprintf(w, "Category: %v\n", vars["category"])
72+
vars := mux.Vars(r)
73+
w.WriteHeader(http.StatusOK)
74+
fmt.Fprintf(w, "Category: %v\n", vars["category"])
7475
}
7576
```
7677

@@ -122,7 +123,7 @@ r.Queries("key", "value")
122123

123124
```go
124125
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
125-
return r.ProtoMajor == 0
126+
return r.ProtoMajor == 0
126127
})
127128
```
128129

@@ -243,24 +244,24 @@ request that matches "/static/*". This makes it easy to serve static files with
243244

244245
```go
245246
func main() {
246-
var dir string
247+
var dir string
247248

248-
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
249-
flag.Parse()
250-
r := mux.NewRouter()
249+
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
250+
flag.Parse()
251+
r := mux.NewRouter()
251252

252-
// This will serve files under http://localhost:8000/static/<filename>
253-
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
253+
// This will serve files under http://localhost:8000/static/<filename>
254+
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
254255

255-
srv := &http.Server{
256-
Handler: r,
257-
Addr: "127.0.0.1:8000",
258-
// Good practice: enforce timeouts for servers you create!
259-
WriteTimeout: 15 * time.Second,
260-
ReadTimeout: 15 * time.Second,
261-
}
256+
srv := &http.Server{
257+
Handler: r,
258+
Addr: "127.0.0.1:8000",
259+
// Good practice: enforce timeouts for servers you create!
260+
WriteTimeout: 15 * time.Second,
261+
ReadTimeout: 15 * time.Second,
262+
}
262263

263-
log.Fatal(srv.ListenAndServe())
264+
log.Fatal(srv.ListenAndServe())
264265
}
265266
```
266267

@@ -383,6 +384,69 @@ r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error
383384
})
384385
```
385386

387+
### Graceful Shutdown
388+
389+
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`:
390+
391+
```go
392+
package main
393+
394+
import (
395+
"context"
396+
"flag"
397+
"log"
398+
"net/http"
399+
"os"
400+
"os/signal"
401+
402+
"github.com/gorilla/mux"
403+
)
404+
405+
func main() {
406+
var wait time.Duration
407+
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")
408+
flag.Parse()
409+
410+
r := mux.NewRouter()
411+
// Add your routes as needed
412+
413+
srv := &http.Server{
414+
Addr: "0.0.0.0:8080",
415+
// Good practice to set timeouts to avoid Slowloris attacks.
416+
WriteTimeout: time.Second * 15,
417+
ReadTimeout: time.Second * 15,
418+
IdleTimeout: time.Second * 60,
419+
Handler: r, // Pass our instance of gorilla/mux in.
420+
}
421+
422+
// Run our server in a goroutine so that it doesn't block.
423+
go func() {
424+
if err := srv.ListenAndServe(); err != nil {
425+
log.Println(err)
426+
}
427+
}()
428+
429+
c := make(chan os.Signal, 1)
430+
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
431+
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
432+
signal.Notify(c, os.Interrupt)
433+
434+
// Block until we receive our signal.
435+
<-c
436+
437+
// Create a deadline to wait for.
438+
ctx, cancel := context.WithTimeout(ctx, wait)
439+
// Doesn't block if no connections, but will otherwise wait
440+
// until the timeout deadline.
441+
srv.Shutdown(ctx)
442+
// Optionally, you could run srv.Shutdown in a goroutine and block on
443+
// <-ctx.Done() if your application should wait for other services
444+
// to finalize based on context cancellation.
445+
log.Println("shutting down")
446+
os.Exit(0)
447+
}
448+
```
449+
386450
## Full Example
387451

388452
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:
391455
package main
392456

393457
import (
394-
"net/http"
395-
"log"
396-
"github.com/gorilla/mux"
458+
"net/http"
459+
"log"
460+
"github.com/gorilla/mux"
397461
)
398462

399463
func YourHandler(w http.ResponseWriter, r *http.Request) {
400-
w.Write([]byte("Gorilla!\n"))
464+
w.Write([]byte("Gorilla!\n"))
401465
}
402466

403467
func main() {
404-
r := mux.NewRouter()
405-
// Routes consist of a path and a handler function.
406-
r.HandleFunc("/", YourHandler)
468+
r := mux.NewRouter()
469+
// Routes consist of a path and a handler function.
470+
r.HandleFunc("/", YourHandler)
407471

408-
// Bind to a port and pass our router in
409-
log.Fatal(http.ListenAndServe(":8000", r))
472+
// Bind to a port and pass our router in
473+
log.Fatal(http.ListenAndServe(":8000", r))
410474
}
411475
```
412476

0 commit comments

Comments
 (0)