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"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
slog "log"
|
slog "log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -51,13 +52,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
"github.com/tylerb/graceful"
|
|
||||||
"golang.org/x/crypto/acme/autocert"
|
"golang.org/x/crypto/acme/autocert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Echo is the top-level framework instance.
|
// Echo is the top-level framework instance.
|
||||||
Echo struct {
|
Echo struct {
|
||||||
|
Server *http.Server
|
||||||
|
TLSServer *http.Server
|
||||||
|
Listener net.Listener
|
||||||
|
TLSListener net.Listener
|
||||||
DisableHTTP2 bool
|
DisableHTTP2 bool
|
||||||
Debug bool
|
Debug bool
|
||||||
HTTPErrorHandler HTTPErrorHandler
|
HTTPErrorHandler HTTPErrorHandler
|
||||||
@ -65,13 +69,8 @@ type (
|
|||||||
Validator Validator
|
Validator Validator
|
||||||
Renderer Renderer
|
Renderer Renderer
|
||||||
AutoTLSManager autocert.Manager
|
AutoTLSManager autocert.Manager
|
||||||
ReadTimeout time.Duration
|
|
||||||
WriteTimeout time.Duration
|
|
||||||
ShutdownTimeout time.Duration
|
|
||||||
Logger Logger
|
Logger Logger
|
||||||
stdLogger *slog.Logger
|
stdLogger *slog.Logger
|
||||||
server *graceful.Server
|
|
||||||
tlsServer *graceful.Server
|
|
||||||
premiddleware []MiddlewareFunc
|
premiddleware []MiddlewareFunc
|
||||||
middleware []MiddlewareFunc
|
middleware []MiddlewareFunc
|
||||||
maxParam *int
|
maxParam *int
|
||||||
@ -239,13 +238,16 @@ var (
|
|||||||
// New creates an instance of Echo.
|
// New creates an instance of Echo.
|
||||||
func New() (e *Echo) {
|
func New() (e *Echo) {
|
||||||
e = &Echo{
|
e = &Echo{
|
||||||
|
Server: new(http.Server),
|
||||||
|
TLSServer: new(http.Server),
|
||||||
AutoTLSManager: autocert.Manager{
|
AutoTLSManager: autocert.Manager{
|
||||||
Prompt: autocert.AcceptTOS,
|
Prompt: autocert.AcceptTOS,
|
||||||
},
|
},
|
||||||
ShutdownTimeout: 15 * time.Second,
|
Logger: log.New("echo"),
|
||||||
Logger: log.New("echo"),
|
maxParam: new(int),
|
||||||
maxParam: new(int),
|
|
||||||
}
|
}
|
||||||
|
e.Server.Handler = e
|
||||||
|
e.TLSServer.Handler = e
|
||||||
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
|
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
|
||||||
e.Binder = &DefaultBinder{}
|
e.Binder = &DefaultBinder{}
|
||||||
e.Logger.SetLevel(log.OFF)
|
e.Logger.SetLevel(log.OFF)
|
||||||
@ -518,76 +520,64 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
e.pool.Put(c)
|
e.pool.Put(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the HTTP server.
|
// Start starts an HTTP server.
|
||||||
func (e *Echo) Start(address string) error {
|
func (e *Echo) Start(address string) error {
|
||||||
return e.StartServer(&http.Server{
|
e.Server.Addr = address
|
||||||
Addr: address,
|
return e.StartServer(e.Server)
|
||||||
ReadTimeout: e.ReadTimeout,
|
|
||||||
WriteTimeout: e.WriteTimeout,
|
|
||||||
ErrorLog: e.stdLogger,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartTLS starts the HTTPS server.
|
// StartTLS starts an HTTPS server.
|
||||||
func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
|
func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
|
||||||
if certFile == "" || keyFile == "" {
|
if certFile == "" || keyFile == "" {
|
||||||
return errors.New("invalid tls configuration")
|
return errors.New("invalid tls configuration")
|
||||||
}
|
}
|
||||||
config := new(tls.Config)
|
s := e.TLSServer
|
||||||
config.Certificates = make([]tls.Certificate, 1)
|
s.TLSConfig = new(tls.Config)
|
||||||
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
s.TLSConfig.Certificates = make([]tls.Certificate, 1)
|
||||||
|
s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
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 {
|
func (e *Echo) StartAutoTLS(address string) error {
|
||||||
config := new(tls.Config)
|
s := e.TLSServer
|
||||||
config.GetCertificate = e.AutoTLSManager.GetCertificate
|
s.TLSConfig = new(tls.Config)
|
||||||
return e.startTLS(address, 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 {
|
if !e.DisableHTTP2 {
|
||||||
config.NextProtos = append(config.NextProtos, "h2")
|
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
|
||||||
}
|
}
|
||||||
return e.StartServer(&http.Server{
|
return e.StartServer(e.TLSServer)
|
||||||
Addr: address,
|
|
||||||
ReadTimeout: e.ReadTimeout,
|
|
||||||
WriteTimeout: e.WriteTimeout,
|
|
||||||
TLSConfig: config,
|
|
||||||
ErrorLog: e.stdLogger,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartServer runs a custom HTTP server.
|
// StartServer starts a custom http server.
|
||||||
func (e *Echo) StartServer(s *http.Server) error {
|
func (e *Echo) StartServer(s *http.Server) error {
|
||||||
s.Handler = e
|
s.Handler = e
|
||||||
gs := &graceful.Server{
|
s.ErrorLog = e.stdLogger
|
||||||
Server: s,
|
l, err := net.Listen("tcp", s.Addr)
|
||||||
Timeout: e.ShutdownTimeout,
|
if err != nil {
|
||||||
Logger: e.stdLogger,
|
return err
|
||||||
}
|
}
|
||||||
if s.TLSConfig == nil {
|
if s.TLSConfig == nil {
|
||||||
e.server = gs
|
if e.Listener == nil {
|
||||||
e.Logger.Printf("http server started on %s", s.Addr)
|
e.Listener = tcpKeepAliveListener{l.(*net.TCPListener)}
|
||||||
return gs.ListenAndServe()
|
}
|
||||||
|
e.Logger.Printf("http server started on %s", e.Server.Addr)
|
||||||
|
return s.Serve(e.Listener)
|
||||||
}
|
}
|
||||||
e.tlsServer = gs
|
if e.TLSListener == nil {
|
||||||
e.Logger.Printf(" ⇛ https server started on %s", s.Addr)
|
e.TLSListener = tls.NewListener(tcpKeepAliveListener{l.(*net.TCPListener)}, s.TLSConfig)
|
||||||
return gs.ListenAndServeTLSConfig(s.TLSConfig)
|
}
|
||||||
}
|
e.Logger.Printf(" ⇛ https server started on %s", e.Server.Addr)
|
||||||
|
return s.Serve(e.TLSListener)
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHTTPError creates a new HTTPError instance.
|
// NewHTTPError creates a new HTTPError instance.
|
||||||
@ -632,3 +622,21 @@ func handlerName(h HandlerFunc) string {
|
|||||||
}
|
}
|
||||||
return t.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"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -392,8 +391,6 @@ func TestEchoStart(t *testing.T) {
|
|||||||
go func() {
|
go func() {
|
||||||
assert.NoError(t, e.Start(":0"))
|
assert.NoError(t, e.Start(":0"))
|
||||||
}()
|
}()
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
e.Shutdown(1 * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoStartTLS(t *testing.T) {
|
func TestEchoStartTLS(t *testing.T) {
|
||||||
@ -401,8 +398,6 @@ func TestEchoStartTLS(t *testing.T) {
|
|||||||
go func() {
|
go func() {
|
||||||
assert.NoError(t, e.StartTLS(":0", "_fixture/certs/cert.pem", "_fixture/certs/key.pem"))
|
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) {
|
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
|
hash: 4a4f41416395516f7eefabd29ee5c7b065a411dec7446f6d6853d4cc28c4c644
|
||||||
updated: 2016-12-25T21:41:41.108263974-08:00
|
updated: 2017-01-13T18:25:37.646516032-08:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/daaku/go.zipexe
|
- name: github.com/daaku/go.zipexe
|
||||||
version: a5fe2436ffcb3236e175e5149162b41cd28bd27d
|
version: a5fe2436ffcb3236e175e5149162b41cd28bd27d
|
||||||
- name: github.com/dgrijalva/jwt-go
|
- 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
|
- name: github.com/GeertJohan/go.rice
|
||||||
version: 9fdfd46f9806a9228aae341d65ab75c5235c383c
|
version: 9fdfd46f9806a9228aae341d65ab75c5235c383c
|
||||||
subpackages:
|
subpackages:
|
||||||
@ -14,11 +25,11 @@ imports:
|
|||||||
subpackages:
|
subpackages:
|
||||||
- proto
|
- proto
|
||||||
- name: github.com/gorilla/websocket
|
- name: github.com/gorilla/websocket
|
||||||
version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13
|
version: 17634340a83afe0cab595e40fbc63f6ffa1d8915
|
||||||
- name: github.com/kardianos/osext
|
- name: github.com/kardianos/osext
|
||||||
version: c2c54e542fb797ad986b31721e1baedf214ca413
|
version: c2c54e542fb797ad986b31721e1baedf214ca413
|
||||||
- name: github.com/labstack/gommon
|
- name: github.com/labstack/gommon
|
||||||
version: b2765095a572012ea4828c9596fefd824c2aee72
|
version: f72d3c883f8ea180da8f085dd320804c41332ad1
|
||||||
subpackages:
|
subpackages:
|
||||||
- bytes
|
- bytes
|
||||||
- color
|
- color
|
||||||
@ -29,16 +40,18 @@ imports:
|
|||||||
- name: github.com/mattn/go-isatty
|
- name: github.com/mattn/go-isatty
|
||||||
version: 30a891c33c7cde7b02a981314b4228ec99380cca
|
version: 30a891c33c7cde7b02a981314b4228ec99380cca
|
||||||
- name: github.com/tylerb/graceful
|
- name: github.com/tylerb/graceful
|
||||||
version: 4df1190835320af7076dfcf27b3d071fd3612caf
|
version: d37e108c89765a8e307f15b8fb2ecd10575da6bb
|
||||||
|
- name: github.com/valyala/bytebufferpool
|
||||||
|
version: e746df99fe4a3986f4d4f79e13c1e0117ce9c2f7
|
||||||
- name: github.com/valyala/fasttemplate
|
- name: github.com/valyala/fasttemplate
|
||||||
version: 3b874956e03f1636d171bda64b130f9135f42cff
|
version: d090d65668a286d9a180d43a19dfdc5dcad8fe88
|
||||||
- name: golang.org/x/crypto
|
- name: golang.org/x/crypto
|
||||||
version: f6b343c37ca80bfa8ea539da67a0b621f84fab1d
|
version: 2f8be38b9a7533b8763d48273737ff6e90428a96
|
||||||
subpackages:
|
subpackages:
|
||||||
- acme
|
- acme
|
||||||
- acme/autocert
|
- acme/autocert
|
||||||
- name: golang.org/x/net
|
- name: golang.org/x/net
|
||||||
version: 45e771701b814666a7eb299e6c7a57d0b1799e91
|
version: c427ad74c6d7a814201695e9ffde0c5d400a7674
|
||||||
subpackages:
|
subpackages:
|
||||||
- context
|
- context
|
||||||
- context/ctxhttp
|
- context/ctxhttp
|
||||||
@ -48,7 +61,7 @@ imports:
|
|||||||
subpackages:
|
subpackages:
|
||||||
- unix
|
- unix
|
||||||
- name: google.golang.org/appengine
|
- name: google.golang.org/appengine
|
||||||
version: 08a149cfaee099e6ce4be01c0113a78c85ee1dee
|
version: 9e2ad0873f358c54296ccdc5116b0652c98226d1
|
||||||
subpackages:
|
subpackages:
|
||||||
- internal
|
- internal
|
||||||
- internal/app_identity
|
- internal/app_identity
|
||||||
|
@ -10,7 +10,6 @@ import:
|
|||||||
- log
|
- log
|
||||||
- random
|
- random
|
||||||
- package: github.com/mattn/go-isatty
|
- package: github.com/mattn/go-isatty
|
||||||
- package: github.com/tylerb/graceful
|
|
||||||
- package: github.com/valyala/fasttemplate
|
- package: github.com/valyala/fasttemplate
|
||||||
- package: golang.org/x/crypto
|
- package: golang.org/x/crypto
|
||||||
subpackages:
|
subpackages:
|
||||||
@ -22,6 +21,7 @@ import:
|
|||||||
- package: gopkg.in/mgo.v2
|
- package: gopkg.in/mgo.v2
|
||||||
subpackages:
|
subpackages:
|
||||||
- bson
|
- bson
|
||||||
|
- package: github.com/facebookgo/grace
|
||||||
testImport:
|
testImport:
|
||||||
- package: github.com/stretchr/testify
|
- package: github.com/stretchr/testify
|
||||||
subpackages:
|
subpackages:
|
||||||
|
@ -7,21 +7,25 @@ description = "Graceful shutdown example for Echo"
|
|||||||
weight = 13
|
weight = 13
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Echo now ships with graceful server termination inside it, to accomplish it Echo
|
## Using [grace](https://github.com/facebookgo/grace)
|
||||||
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:
|
|
||||||
|
|
||||||
`server.go`
|
`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
|
## Source Code
|
||||||
|
|
||||||
- [graceful]({{< source "graceful-shutdown/graceful" >}})
|
- [graceful]({{< source "graceful-shutdown/graceful" >}})
|
||||||
|
- [grace]({{< source "graceful-shutdown/grace" >}})
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
|
|
||||||
- [mertenvg](https://github.com/mertenvg)
|
- [mertenvg](https://github.com/mertenvg)
|
||||||
- [apaganobeleno](https://github.com/apaganobeleno)
|
- [apaganobeleno](https://github.com/apaganobeleno)
|
||||||
|
- [vishr](https://github.com/vishr)
|
||||||
|
@ -77,20 +77,14 @@ e.Logger.Fatal(s.ListenAndServe())
|
|||||||
|
|
||||||
## Read Timeout
|
## 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.
|
of the request.
|
||||||
|
|
||||||
## Write Timeout
|
## 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.
|
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
|
## Validator
|
||||||
|
|
||||||
`Echo#Validator` can be used to register a validator for performing data validation
|
`Echo#Validator` can be used to register a validator for performing data validation
|
||||||
|
Loading…
Reference in New Issue
Block a user