mirror of
https://github.com/labstack/echo.git
synced 2025-01-12 01:22:21 +02:00
gc
Removed graceful shutdown, fixed #797 Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
8526358e8a
commit
9797cf4b9c
118
echo.go
118
echo.go
@ -43,6 +43,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
slog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"path"
|
||||
"reflect"
|
||||
@ -51,13 +52,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/labstack/gommon/log"
|
||||
"github.com/tylerb/graceful"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
type (
|
||||
// Echo is the top-level framework instance.
|
||||
Echo struct {
|
||||
Server *http.Server
|
||||
TLSServer *http.Server
|
||||
Listener net.Listener
|
||||
TLSListener net.Listener
|
||||
DisableHTTP2 bool
|
||||
Debug bool
|
||||
HTTPErrorHandler HTTPErrorHandler
|
||||
@ -65,13 +69,8 @@ type (
|
||||
Validator Validator
|
||||
Renderer Renderer
|
||||
AutoTLSManager autocert.Manager
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
ShutdownTimeout time.Duration
|
||||
Logger Logger
|
||||
stdLogger *slog.Logger
|
||||
server *graceful.Server
|
||||
tlsServer *graceful.Server
|
||||
premiddleware []MiddlewareFunc
|
||||
middleware []MiddlewareFunc
|
||||
maxParam *int
|
||||
@ -239,13 +238,16 @@ var (
|
||||
// New creates an instance of Echo.
|
||||
func New() (e *Echo) {
|
||||
e = &Echo{
|
||||
Server: new(http.Server),
|
||||
TLSServer: new(http.Server),
|
||||
AutoTLSManager: autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
},
|
||||
ShutdownTimeout: 15 * time.Second,
|
||||
Logger: log.New("echo"),
|
||||
maxParam: new(int),
|
||||
Logger: log.New("echo"),
|
||||
maxParam: new(int),
|
||||
}
|
||||
e.Server.Handler = e
|
||||
e.TLSServer.Handler = e
|
||||
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
|
||||
e.Binder = &DefaultBinder{}
|
||||
e.Logger.SetLevel(log.OFF)
|
||||
@ -518,76 +520,64 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
e.pool.Put(c)
|
||||
}
|
||||
|
||||
// Start starts the HTTP server.
|
||||
// Start starts an HTTP server.
|
||||
func (e *Echo) Start(address string) error {
|
||||
return e.StartServer(&http.Server{
|
||||
Addr: address,
|
||||
ReadTimeout: e.ReadTimeout,
|
||||
WriteTimeout: e.WriteTimeout,
|
||||
ErrorLog: e.stdLogger,
|
||||
})
|
||||
e.Server.Addr = address
|
||||
return e.StartServer(e.Server)
|
||||
}
|
||||
|
||||
// StartTLS starts the HTTPS server.
|
||||
// StartTLS starts an HTTPS server.
|
||||
func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
|
||||
if certFile == "" || keyFile == "" {
|
||||
return errors.New("invalid tls configuration")
|
||||
}
|
||||
config := new(tls.Config)
|
||||
config.Certificates = make([]tls.Certificate, 1)
|
||||
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||
s := e.TLSServer
|
||||
s.TLSConfig = new(tls.Config)
|
||||
s.TLSConfig.Certificates = make([]tls.Certificate, 1)
|
||||
s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return e.startTLS(address, config)
|
||||
return e.startTLS(address)
|
||||
}
|
||||
|
||||
// StartAutoTLS starts the HTTPS server using certificates automatically from https://letsencrypt.org.
|
||||
// StartAutoTLS starts an HTTPS server using certificates automatically from https://letsencrypt.org.
|
||||
func (e *Echo) StartAutoTLS(address string) error {
|
||||
config := new(tls.Config)
|
||||
config.GetCertificate = e.AutoTLSManager.GetCertificate
|
||||
return e.startTLS(address, config)
|
||||
s := e.TLSServer
|
||||
s.TLSConfig = new(tls.Config)
|
||||
s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
|
||||
return e.startTLS(address)
|
||||
}
|
||||
|
||||
func (e *Echo) startTLS(address string, config *tls.Config) error {
|
||||
func (e *Echo) startTLS(address string) error {
|
||||
s := e.TLSServer
|
||||
s.Addr = address
|
||||
if !e.DisableHTTP2 {
|
||||
config.NextProtos = append(config.NextProtos, "h2")
|
||||
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
|
||||
}
|
||||
return e.StartServer(&http.Server{
|
||||
Addr: address,
|
||||
ReadTimeout: e.ReadTimeout,
|
||||
WriteTimeout: e.WriteTimeout,
|
||||
TLSConfig: config,
|
||||
ErrorLog: e.stdLogger,
|
||||
})
|
||||
return e.StartServer(e.TLSServer)
|
||||
}
|
||||
|
||||
// StartServer runs a custom HTTP server.
|
||||
// StartServer starts a custom http server.
|
||||
func (e *Echo) StartServer(s *http.Server) error {
|
||||
s.Handler = e
|
||||
gs := &graceful.Server{
|
||||
Server: s,
|
||||
Timeout: e.ShutdownTimeout,
|
||||
Logger: e.stdLogger,
|
||||
s.ErrorLog = e.stdLogger
|
||||
l, err := net.Listen("tcp", s.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.TLSConfig == nil {
|
||||
e.server = gs
|
||||
e.Logger.Printf("http server started on %s", s.Addr)
|
||||
return gs.ListenAndServe()
|
||||
if e.Listener == nil {
|
||||
e.Listener = tcpKeepAliveListener{l.(*net.TCPListener)}
|
||||
}
|
||||
e.Logger.Printf("http server started on %s", e.Server.Addr)
|
||||
return s.Serve(e.Listener)
|
||||
}
|
||||
e.tlsServer = gs
|
||||
e.Logger.Printf(" ⇛ https server started on %s", s.Addr)
|
||||
return gs.ListenAndServeTLSConfig(s.TLSConfig)
|
||||
}
|
||||
|
||||
// Shutdown gracefully shutdown the HTTP server with timeout.
|
||||
func (e *Echo) Shutdown(timeout time.Duration) {
|
||||
e.server.Stop(timeout)
|
||||
}
|
||||
|
||||
// ShutdownTLS gracefully shutdown the TLS server with timeout.
|
||||
func (e *Echo) ShutdownTLS(timeout time.Duration) {
|
||||
e.tlsServer.Stop(timeout)
|
||||
if e.TLSListener == nil {
|
||||
e.TLSListener = tls.NewListener(tcpKeepAliveListener{l.(*net.TCPListener)}, s.TLSConfig)
|
||||
}
|
||||
e.Logger.Printf(" ⇛ https server started on %s", e.Server.Addr)
|
||||
return s.Serve(e.TLSListener)
|
||||
}
|
||||
|
||||
// NewHTTPError creates a new HTTPError instance.
|
||||
@ -632,3 +622,21 @@ func handlerName(h HandlerFunc) string {
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||
// connections. It's used by ListenAndServe and ListenAndServeTLS so
|
||||
// dead TCP connections (e.g. closing laptop mid-download) eventually
|
||||
// go away.
|
||||
type tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
tc, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tc.SetKeepAlive(true)
|
||||
tc.SetKeepAlivePeriod(3 * time.Minute)
|
||||
return tc, nil
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -392,8 +391,6 @@ func TestEchoStart(t *testing.T) {
|
||||
go func() {
|
||||
assert.NoError(t, e.Start(":0"))
|
||||
}()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
e.Shutdown(1 * time.Second)
|
||||
}
|
||||
|
||||
func TestEchoStartTLS(t *testing.T) {
|
||||
@ -401,8 +398,6 @@ func TestEchoStartTLS(t *testing.T) {
|
||||
go func() {
|
||||
assert.NoError(t, e.StartTLS(":0", "_fixture/certs/cert.pem", "_fixture/certs/key.pem"))
|
||||
}()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
e.ShutdownTLS(1 * time.Second)
|
||||
}
|
||||
|
||||
func testMethod(t *testing.T, method, path string, e *Echo) {
|
||||
|
20
examples/graceful-shutdown/grace/server.go
Normal file
20
examples/graceful-shutdown/grace/server.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/facebookgo/grace/gracehttp"
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Setup
|
||||
e := echo.New()
|
||||
e.GET("/", func(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "Six sick bricks tick")
|
||||
})
|
||||
e.Server.Addr = ":1323"
|
||||
|
||||
// Serve it like a boss
|
||||
e.Logger.Fatal(gracehttp.Serve(e.Server))
|
||||
}
|
21
examples/graceful-shutdown/graceful/server.go
Normal file
21
examples/graceful-shutdown/graceful/server.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo"
|
||||
"github.com/tylerb/graceful"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Setup
|
||||
e := echo.New()
|
||||
e.GET("/", func(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "Sue sews rose on slow joe crows nose")
|
||||
})
|
||||
e.Server.Addr = ":1323"
|
||||
|
||||
// Serve it like a boss
|
||||
graceful.ListenAndServe(e.Server, 5*time.Second)
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
e := echo.New()
|
||||
|
||||
// Setting up the termination timeout to 30 seconds.
|
||||
e.ShutdownTimeout = 30 * time.Second
|
||||
|
||||
e.GET("/", func(ctx echo.Context) error {
|
||||
return ctx.String(200, "OK")
|
||||
})
|
||||
|
||||
e.Logger.Fatal(e.Start(":1323"))
|
||||
}
|
33
glide.lock
generated
33
glide.lock
generated
@ -1,10 +1,21 @@
|
||||
hash: 23f3636cfa67541062f212b8285762ca142c6bb55889f243bf0574ba00e0ff92
|
||||
updated: 2016-12-25T21:41:41.108263974-08:00
|
||||
hash: 4a4f41416395516f7eefabd29ee5c7b065a411dec7446f6d6853d4cc28c4c644
|
||||
updated: 2017-01-13T18:25:37.646516032-08:00
|
||||
imports:
|
||||
- name: github.com/daaku/go.zipexe
|
||||
version: a5fe2436ffcb3236e175e5149162b41cd28bd27d
|
||||
- name: github.com/dgrijalva/jwt-go
|
||||
version: 9ed569b5d1ac936e6494082958d63a6aa4fff99a
|
||||
version: a601269ab70c205d26370c16f7c81e9017c14e04
|
||||
- name: github.com/facebookgo/clock
|
||||
version: 600d898af40aa09a7a93ecb9265d87b0504b6f03
|
||||
- name: github.com/facebookgo/grace
|
||||
version: 5729e484473f52048578af1b80d0008c7024089b
|
||||
subpackages:
|
||||
- gracehttp
|
||||
- gracenet
|
||||
- name: github.com/facebookgo/httpdown
|
||||
version: a3b1354551a26449fbe05f5d855937f6e7acbd71
|
||||
- name: github.com/facebookgo/stats
|
||||
version: 1b76add642e42c6ffba7211ad7b3939ce654526e
|
||||
- name: github.com/GeertJohan/go.rice
|
||||
version: 9fdfd46f9806a9228aae341d65ab75c5235c383c
|
||||
subpackages:
|
||||
@ -14,11 +25,11 @@ imports:
|
||||
subpackages:
|
||||
- proto
|
||||
- name: github.com/gorilla/websocket
|
||||
version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13
|
||||
version: 17634340a83afe0cab595e40fbc63f6ffa1d8915
|
||||
- name: github.com/kardianos/osext
|
||||
version: c2c54e542fb797ad986b31721e1baedf214ca413
|
||||
- name: github.com/labstack/gommon
|
||||
version: b2765095a572012ea4828c9596fefd824c2aee72
|
||||
version: f72d3c883f8ea180da8f085dd320804c41332ad1
|
||||
subpackages:
|
||||
- bytes
|
||||
- color
|
||||
@ -29,16 +40,18 @@ imports:
|
||||
- name: github.com/mattn/go-isatty
|
||||
version: 30a891c33c7cde7b02a981314b4228ec99380cca
|
||||
- name: github.com/tylerb/graceful
|
||||
version: 4df1190835320af7076dfcf27b3d071fd3612caf
|
||||
version: d37e108c89765a8e307f15b8fb2ecd10575da6bb
|
||||
- name: github.com/valyala/bytebufferpool
|
||||
version: e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7
|
||||
- name: github.com/valyala/fasttemplate
|
||||
version: 3b874956e03f1636d171bda64b130f9135f42cff
|
||||
version: d090d65668a286d9a180d43a19dfdc5dcad8fe88
|
||||
- name: golang.org/x/crypto
|
||||
version: f6b343c37ca80bfa8ea539da67a0b621f84fab1d
|
||||
version: 2f8be38b9a7533b8763d48273737ff6e90428a96
|
||||
subpackages:
|
||||
- acme
|
||||
- acme/autocert
|
||||
- name: golang.org/x/net
|
||||
version: 45e771701b814666a7eb299e6c7a57d0b1799e91
|
||||
version: c427ad74c6d7a814201695e9ffde0c5d400a7674
|
||||
subpackages:
|
||||
- context
|
||||
- context/ctxhttp
|
||||
@ -48,7 +61,7 @@ imports:
|
||||
subpackages:
|
||||
- unix
|
||||
- name: google.golang.org/appengine
|
||||
version: 08a149cfaee099e6ce4be01c0113a78c85ee1dee
|
||||
version: 9e2ad0873f358c54296ccdc5116b0652c98226d1
|
||||
subpackages:
|
||||
- internal
|
||||
- internal/app_identity
|
||||
|
@ -10,7 +10,6 @@ import:
|
||||
- log
|
||||
- random
|
||||
- package: github.com/mattn/go-isatty
|
||||
- package: github.com/tylerb/graceful
|
||||
- package: github.com/valyala/fasttemplate
|
||||
- package: golang.org/x/crypto
|
||||
subpackages:
|
||||
@ -22,6 +21,7 @@ import:
|
||||
- package: gopkg.in/mgo.v2
|
||||
subpackages:
|
||||
- bson
|
||||
- package: github.com/facebookgo/grace
|
||||
testImport:
|
||||
- package: github.com/stretchr/testify
|
||||
subpackages:
|
||||
|
@ -7,21 +7,25 @@ description = "Graceful shutdown example for Echo"
|
||||
weight = 13
|
||||
+++
|
||||
|
||||
Echo now ships with graceful server termination inside it, to accomplish it Echo
|
||||
uses `github.com/tylerb/graceful` library. By Default echo uses 15 seconds as shutdown
|
||||
timeout, giving 15 secs to open connections at the time the server starts to shut-down.
|
||||
In order to change this default 15 seconds you could change the `ShutdownTimeout`
|
||||
property of your Echo instance as needed by doing something like:
|
||||
## Using [grace](https://github.com/facebookgo/grace)
|
||||
|
||||
`server.go`
|
||||
|
||||
{{< embed "graceful-shutdown/server.go" >}}
|
||||
{{< embed "graceful-shutdown/grace/server.go" >}}
|
||||
|
||||
## Using [graceful](https://github.com/tylerb/graceful)
|
||||
|
||||
`server.go`
|
||||
|
||||
{{< embed "graceful-shutdown/graceful/server.go" >}}
|
||||
|
||||
## Source Code
|
||||
|
||||
- [graceful]({{< source "graceful-shutdown/graceful" >}})
|
||||
- [grace]({{< source "graceful-shutdown/grace" >}})
|
||||
|
||||
## Maintainers
|
||||
|
||||
- [mertenvg](https://github.com/mertenvg)
|
||||
- [apaganobeleno](https://github.com/apaganobeleno)
|
||||
- [vishr](https://github.com/vishr)
|
||||
|
@ -77,20 +77,14 @@ e.Logger.Fatal(s.ListenAndServe())
|
||||
|
||||
## Read Timeout
|
||||
|
||||
`Echo#ReadTimeout` can be used to set the maximum duration before timing out read
|
||||
`Echo#*Server#ReadTimeout` can be used to set the maximum duration before timing out read
|
||||
of the request.
|
||||
|
||||
## Write Timeout
|
||||
|
||||
`Echo#WriteTimeout` can be used to set the maximum duration before timing out write
|
||||
`Echo#*Server#WriteTimeout` can be used to set the maximum duration before timing out write
|
||||
of the response.
|
||||
|
||||
## Shutdown Timeout
|
||||
|
||||
`Echo#ShutdownTimeout` can be used to set the maximum duration to wait until killing
|
||||
active requests and stopping the server. If timeout is 0, the server never times
|
||||
out. It waits for all active requests to finish.
|
||||
|
||||
## Validator
|
||||
|
||||
`Echo#Validator` can be used to register a validator for performing data validation
|
||||
|
Loading…
Reference in New Issue
Block a user