Toggle /ping to artificially return unhealthy response on SIGTERM during requestAcceptGraceTimeout interval

This commit is contained in:
ravilr 2018-03-22 10:18:03 -07:00 committed by Traefiker Bot
parent 9699dc2a85
commit 5792a19b97
5 changed files with 45 additions and 4 deletions

View file

@ -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`.
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.

View file

@ -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))
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.
proc, err := os.FindProcess(cmd.Process.Pid)
c.Assert(err, checker.IsNil)
@ -143,6 +147,12 @@ func (s *SimpleSuite) TestRequestAcceptGraceTimeout(c *check.C) {
defer resp.Body.Close()
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
// period has elapsed.
waitErr := make(chan error)

View file

@ -6,6 +6,9 @@ logLevel = "DEBUG"
[entryPoints.http]
address = ":8000"
[entryPoints.traefik]
address = ":8001"
[lifeCycle]
requestAcceptGraceTimeout = "10s"
@ -20,3 +23,5 @@ logLevel = "DEBUG"
backend = "backend"
[frontends.frontend.routes.service]
rule = "Path:/service"
[ping]

View file

@ -3,19 +3,38 @@ package ping
import (
"fmt"
"net/http"
"sync"
"github.com/containous/mux"
)
//Handler expose ping routes
// Handler expose ping routes
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
func (g Handler) AddRoutes(router *mux.Router) {
func (g *Handler) AddRoutes(router *mux.Router) {
router.Methods(http.MethodGet, http.MethodHead).Path("/ping").
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))
})
}

View file

@ -212,6 +212,9 @@ func (s *Server) StartWithContext(ctx context.Context) {
<-ctx.Done()
log.Info("I have to go...")
reqAcceptGraceTimeOut := time.Duration(s.globalConfiguration.LifeCycle.RequestAcceptGraceTimeout)
if s.globalConfiguration.Ping != nil && reqAcceptGraceTimeOut > 0 {
s.globalConfiguration.Ping.SetTerminating()
}
if reqAcceptGraceTimeOut > 0 {
log.Infof("Waiting %s for incoming requests to cease", reqAcceptGraceTimeOut)
time.Sleep(reqAcceptGraceTimeOut)