Toggle /ping to artificially return unhealthy response on SIGTERM during requestAcceptGraceTimeout interval
This commit is contained in:
parent
9699dc2a85
commit
5792a19b97
5 changed files with 45 additions and 4 deletions
|
@ -85,3 +85,7 @@ Note the dedicated port `:8082` for `/ping`.
|
||||||
|
|
||||||
In the above example, it is _very_ important to create a named dedicated entry point, and do **not** include it in `defaultEntryPoints`.
|
In the above example, it is _very_ important to create a named dedicated entry point, and do **not** include it in `defaultEntryPoints`.
|
||||||
Otherwise, you are likely to expose _all_ services via this entry point.
|
Otherwise, you are likely to expose _all_ services via this entry point.
|
||||||
|
|
||||||
|
### Using ping for external Load-balancer rotation health check
|
||||||
|
|
||||||
|
If you are running traefik behind a external Load-balancer, and want to configure rotation health check on the Load-balancer to take a traefik instance out of rotation gracefully, you can configure [lifecycle.requestAcceptGraceTimeout](/configuration/commons.md#life-cycle) and the ping endpoint will return `503` response on traefik server termination, so that the Load-balancer can take the terminating traefik instance out of rotation, before it stops responding.
|
||||||
|
|
|
@ -128,6 +128,10 @@ func (s *SimpleSuite) TestRequestAcceptGraceTimeout(c *check.C) {
|
||||||
err = try.GetRequest("http://127.0.0.1:8000/service", 3*time.Second, try.StatusCodeIs(http.StatusOK))
|
err = try.GetRequest("http://127.0.0.1:8000/service", 3*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// Check that /ping endpoint is responding with 200.
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8001/ping", 3*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
// Send SIGTERM to Traefik.
|
// Send SIGTERM to Traefik.
|
||||||
proc, err := os.FindProcess(cmd.Process.Pid)
|
proc, err := os.FindProcess(cmd.Process.Pid)
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
@ -143,6 +147,12 @@ func (s *SimpleSuite) TestRequestAcceptGraceTimeout(c *check.C) {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
|
||||||
|
|
||||||
|
// ping endpoint should now return a Service Unavailable.
|
||||||
|
resp, err = http.Get("http://127.0.0.1:8001/ping")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, http.StatusServiceUnavailable)
|
||||||
|
|
||||||
// Expect Traefik to shut down gracefully once the request accepting grace
|
// Expect Traefik to shut down gracefully once the request accepting grace
|
||||||
// period has elapsed.
|
// period has elapsed.
|
||||||
waitErr := make(chan error)
|
waitErr := make(chan error)
|
||||||
|
|
|
@ -6,6 +6,9 @@ logLevel = "DEBUG"
|
||||||
[entryPoints.http]
|
[entryPoints.http]
|
||||||
address = ":8000"
|
address = ":8000"
|
||||||
|
|
||||||
|
[entryPoints.traefik]
|
||||||
|
address = ":8001"
|
||||||
|
|
||||||
[lifeCycle]
|
[lifeCycle]
|
||||||
requestAcceptGraceTimeout = "10s"
|
requestAcceptGraceTimeout = "10s"
|
||||||
|
|
||||||
|
@ -20,3 +23,5 @@ logLevel = "DEBUG"
|
||||||
backend = "backend"
|
backend = "backend"
|
||||||
[frontends.frontend.routes.service]
|
[frontends.frontend.routes.service]
|
||||||
rule = "Path:/service"
|
rule = "Path:/service"
|
||||||
|
|
||||||
|
[ping]
|
||||||
|
|
27
ping/ping.go
27
ping/ping.go
|
@ -3,19 +3,38 @@ package ping
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/containous/mux"
|
"github.com/containous/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Handler expose ping routes
|
// Handler expose ping routes
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
EntryPoint string `description:"Ping entryPoint" export:"true"`
|
EntryPoint string `description:"Ping entryPoint" export:"true"`
|
||||||
|
terminating bool
|
||||||
|
lock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTerminating causes the ping endpoint to serve non 200 responses.
|
||||||
|
func (g *Handler) SetTerminating() {
|
||||||
|
g.lock.Lock()
|
||||||
|
defer g.lock.Unlock()
|
||||||
|
|
||||||
|
g.terminating = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRoutes add ping routes on a router
|
// AddRoutes add ping routes on a router
|
||||||
func (g Handler) AddRoutes(router *mux.Router) {
|
func (g *Handler) AddRoutes(router *mux.Router) {
|
||||||
router.Methods(http.MethodGet, http.MethodHead).Path("/ping").
|
router.Methods(http.MethodGet, http.MethodHead).Path("/ping").
|
||||||
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
||||||
fmt.Fprint(response, "OK")
|
g.lock.RLock()
|
||||||
|
defer g.lock.RUnlock()
|
||||||
|
|
||||||
|
statusCode := http.StatusOK
|
||||||
|
if g.terminating {
|
||||||
|
statusCode = http.StatusServiceUnavailable
|
||||||
|
}
|
||||||
|
response.WriteHeader(statusCode)
|
||||||
|
fmt.Fprint(response, http.StatusText(statusCode))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,9 @@ func (s *Server) StartWithContext(ctx context.Context) {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
log.Info("I have to go...")
|
log.Info("I have to go...")
|
||||||
reqAcceptGraceTimeOut := time.Duration(s.globalConfiguration.LifeCycle.RequestAcceptGraceTimeout)
|
reqAcceptGraceTimeOut := time.Duration(s.globalConfiguration.LifeCycle.RequestAcceptGraceTimeout)
|
||||||
|
if s.globalConfiguration.Ping != nil && reqAcceptGraceTimeOut > 0 {
|
||||||
|
s.globalConfiguration.Ping.SetTerminating()
|
||||||
|
}
|
||||||
if reqAcceptGraceTimeOut > 0 {
|
if reqAcceptGraceTimeOut > 0 {
|
||||||
log.Infof("Waiting %s for incoming requests to cease", reqAcceptGraceTimeOut)
|
log.Infof("Waiting %s for incoming requests to cease", reqAcceptGraceTimeOut)
|
||||||
time.Sleep(reqAcceptGraceTimeOut)
|
time.Sleep(reqAcceptGraceTimeOut)
|
||||||
|
|
Loading…
Add table
Reference in a new issue