diff --git a/cookbook/graceful-shutdown/server.go b/cookbook/graceful-shutdown/server.go new file mode 100644 index 00000000..3b9828c7 --- /dev/null +++ b/cookbook/graceful-shutdown/server.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + + "os" + "os/signal" + + "time" + + "net/http" + + "github.com/labstack/echo" + "github.com/labstack/gommon/log" +) + +func main() { + // Setup + e := echo.New() + e.Logger.SetLevel(log.INFO) + e.GET("/", func(c echo.Context) error { + time.Sleep(5 * time.Second) + return c.JSON(http.StatusOK, "OK") + }) + + // Start server + go func() { + if err := e.Start(":1323"); err != nil { + e.Logger.Info("shutting down the server") + } + }() + + // Wait for interrupt signal to gracefully shutdown the server with + // a timeout of 10 seconds. + quit := make(chan os.Signal) + signal.Notify(quit, os.Interrupt) + <-quit + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := e.Shutdown(ctx); err != nil { + e.Logger.Fatal(err) + } +} diff --git a/echo_go1.8.go b/echo_go1.8.go new file mode 100644 index 00000000..340bed70 --- /dev/null +++ b/echo_go1.8.go @@ -0,0 +1,25 @@ +// +build go1.8 + +package echo + +import ( + stdContext "context" +) + +// Close immediately stops the server. +// It internally calls `http.Server#Close()`. +func (e *Echo) Close() error { + if err := e.TLSServer.Close(); err != nil { + return err + } + return e.Server.Close() +} + +// Shutdown stops server the gracefully. +// It internally calls `http.Server#Shutdown()`. +func (e *Echo) Shutdown(ctx stdContext.Context) error { + if err := e.TLSServer.Shutdown(ctx); err != nil { + return err + } + return e.Server.Shutdown(ctx) +} diff --git a/echo_go1.8_test.go b/echo_go1.8_test.go new file mode 100644 index 00000000..1191c643 --- /dev/null +++ b/echo_go1.8_test.go @@ -0,0 +1,30 @@ +// +build go1.8 + +package echo + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestEchoClose(t *testing.T) { + e := New() + errCh := make(chan error) + + go func() { + errCh <- e.Start(":0") + }() + + time.Sleep(200 * time.Millisecond) + + if err := e.Close(); err != nil { + t.Fatal(err) + } + + assert.NoError(t, e.Close()) + + err := <-errCh + assert.Equal(t, err.Error(), "http: Server closed") +} diff --git a/website/content/cookbook/graceful-shutdown.md b/website/content/cookbook/graceful-shutdown.md index b10a76c2..d2f5686b 100644 --- a/website/content/cookbook/graceful-shutdown.md +++ b/website/content/cookbook/graceful-shutdown.md @@ -7,6 +7,14 @@ description = "Graceful shutdown example for Echo" weight = 13 +++ +## Using [http.Server#Shutdown()](https://golang.org/pkg/net/http/#Server.Shutdown) + +`server.go` + +{{< embed "graceful-shutdown/server.go" >}} + +> Requires go1.8+ + ## Using [grace](https://github.com/facebookgo/grace) `server.go`