Skip to content

Commit

Permalink
Handle respondingtimeout and better shutdown tests.
Browse files Browse the repository at this point in the history
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
  • Loading branch information
2 people authored and traefiker committed Jan 6, 2020
1 parent 0837ec9 commit 807dc46
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 120 deletions.
2 changes: 1 addition & 1 deletion cmd/traefik/traefik.go
Expand Up @@ -172,7 +172,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err

acmeProviders := initACMEProvider(staticConfiguration, &providerAggregator, tlsManager)

serverEntryPointsTCP, err := server.NewTCPEntryPoints(*staticConfiguration)
serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints)
if err != nil {
return nil, err
}
Expand Down
86 changes: 53 additions & 33 deletions pkg/server/server_entrypoint_tcp.go
Expand Up @@ -52,9 +52,9 @@ func (h *httpForwarder) Accept() (net.Conn, error) {
type TCPEntryPoints map[string]*TCPEntryPoint

// NewTCPEntryPoints creates a new TCPEntryPoints.
func NewTCPEntryPoints(staticConfiguration static.Configuration) (TCPEntryPoints, error) {
func NewTCPEntryPoints(entryPointsConfig static.EntryPoints) (TCPEntryPoints, error) {
serverEntryPointsTCP := make(TCPEntryPoints)
for entryPointName, config := range staticConfiguration.EntryPoints {
for entryPointName, config := range entryPointsConfig {
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))

var err error
Expand Down Expand Up @@ -171,6 +171,23 @@ func (e *TCPEntryPoint) StartTCP(ctx context.Context) {
}

safe.Go(func() {
// Enforce read/write deadlines at the connection level,
// because when we're peeking the first byte to determine whether we are doing TLS,
// the deadlines at the server level are not taken into account.
if e.transportConfiguration.RespondingTimeouts.ReadTimeout > 0 {
err := writeCloser.SetReadDeadline(time.Now().Add(time.Duration(e.transportConfiguration.RespondingTimeouts.ReadTimeout)))
if err != nil {
logger.Errorf("Error while setting read deadline: %v", err)
}
}

if e.transportConfiguration.RespondingTimeouts.WriteTimeout > 0 {
err = writeCloser.SetWriteDeadline(time.Now().Add(time.Duration(e.transportConfiguration.RespondingTimeouts.WriteTimeout)))
if err != nil {
logger.Errorf("Error while setting write deadline: %v", err)
}
}

e.switcher.ServeTCP(newTrackedConnection(writeCloser, e.tracker))
})
}
Expand All @@ -191,48 +208,48 @@ func (e *TCPEntryPoint) Shutdown(ctx context.Context) {
logger.Debugf("Waiting %s seconds before killing connections.", graceTimeOut)

var wg sync.WaitGroup

shutdownServer := func(server stoppableServer) {
defer wg.Done()
err := server.Shutdown(ctx)
if err == nil {
return
}
if ctx.Err() == context.DeadlineExceeded {
logger.Debugf("Server failed to shutdown within deadline because: %s", err)
if err = server.Close(); err != nil {
logger.Error(err)
}
return
}
logger.Error(err)
// We expect Close to fail again because Shutdown most likely failed when trying to close a listener.
// We still call it however, to make sure that all connections get closed as well.
server.Close()
}

if e.httpServer.Server != nil {
wg.Add(1)
go func() {
defer wg.Done()
if err := e.httpServer.Server.Shutdown(ctx); err != nil {
if ctx.Err() == context.DeadlineExceeded {
logger.Debugf("Wait server shutdown is overdue to: %s", err)
err = e.httpServer.Server.Close()
if err != nil {
logger.Error(err)
}
}
}
}()
go shutdownServer(e.httpServer.Server)
}

if e.httpsServer.Server != nil {
wg.Add(1)
go func() {
defer wg.Done()
if err := e.httpsServer.Server.Shutdown(ctx); err != nil {
if ctx.Err() == context.DeadlineExceeded {
logger.Debugf("Wait server shutdown is overdue to: %s", err)
err = e.httpsServer.Server.Close()
if err != nil {
logger.Error(err)
}
}
}
}()
go shutdownServer(e.httpsServer.Server)
}

if e.tracker != nil {
wg.Add(1)
go func() {
defer wg.Done()
if err := e.tracker.Shutdown(ctx); err != nil {
if ctx.Err() == context.DeadlineExceeded {
logger.Debugf("Wait hijack connection is overdue to: %s", err)
e.tracker.Close()
}
err := e.tracker.Shutdown(ctx)
if err == nil {
return
}
if ctx.Err() == context.DeadlineExceeded {
logger.Debugf("Server failed to shutdown before deadline because: %s", err)
}
e.tracker.Close()
}()
}

Expand Down Expand Up @@ -459,8 +476,11 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati
}

serverHTTP := &http.Server{
Handler: handler,
ErrorLog: httpServerLogger,
Handler: handler,
ErrorLog: httpServerLogger,
ReadTimeout: time.Duration(configuration.Transport.RespondingTimeouts.ReadTimeout),
WriteTimeout: time.Duration(configuration.Transport.RespondingTimeouts.WriteTimeout),
IdleTimeout: time.Duration(configuration.Transport.RespondingTimeouts.IdleTimeout),
}

listener := newHTTPForwarder(ln)
Expand Down

0 comments on commit 807dc46

Please sign in to comment.