introduce reader deadlines for net.Conn (#19023)

Bonus: set "retry-after" header for AWS SDKs if possible to honor them.
This commit is contained in:
Harshavardhana
2024-02-09 13:25:16 -08:00
committed by GitHub
parent 8e68ff9321
commit 997ba3a574
12 changed files with 183 additions and 142 deletions

View File

@@ -22,6 +22,9 @@ import (
"fmt"
"net"
"syscall"
"time"
"github.com/minio/minio/internal/deadlineconn"
)
type acceptResult struct {
@@ -32,6 +35,7 @@ type acceptResult struct {
// httpListener - HTTP listener capable of handling multiple server addresses.
type httpListener struct {
opts TCPOptions
tcpListeners []*net.TCPListener // underlying TCP listeners.
acceptCh chan acceptResult // channel where all TCP listeners write accepted connection.
ctx context.Context
@@ -74,7 +78,8 @@ func (listener *httpListener) Accept() (conn net.Conn, err error) {
select {
case result, ok := <-listener.acceptCh:
if ok {
return result.conn, result.err
return deadlineconn.New(result.conn).
WithReadDeadline(listener.opts.ClientReadTimeout), result.err
}
case <-listener.ctx.Done():
}
@@ -119,9 +124,10 @@ func (listener *httpListener) Addrs() (addrs []net.Addr) {
// TCPOptions specify customizable TCP optimizations on raw socket
type TCPOptions struct {
UserTimeout int // this value is expected to be in milliseconds
Interface string // this is a VRF device passed via `--interface` flag
Trace func(msg string) // Trace when starting.
UserTimeout int // this value is expected to be in milliseconds
ClientReadTimeout time.Duration // When the net.Conn is idle for more than ReadTimeout duration, we close the connection on the client proactively.
Interface string // this is a VRF device passed via `--interface` flag
Trace func(msg string) // Trace when starting.
}
// newHTTPListener - creates new httpListener object which is interface compatible to net.Listener.
@@ -173,6 +179,7 @@ func newHTTPListener(ctx context.Context, serverAddrs []string, opts TCPOptions)
listener = &httpListener{
tcpListeners: tcpListeners,
acceptCh: make(chan acceptResult, len(tcpListeners)),
opts: opts,
}
listener.ctx, listener.ctxCanceler = context.WithCancel(ctx)
if opts.Trace != nil {

View File

@@ -109,8 +109,12 @@ func (srv *Server) Init(listenCtx context.Context, listenErrCallback func(listen
wrappedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// If server is in shutdown.
if atomic.LoadUint32(&srv.inShutdown) != 0 {
// To indicate disable keep-alive
// To indicate disable keep-alive, server is shutting down.
w.Header().Set("Connection", "close")
// Add 1 minute retry header, incase-client wants to honor it
w.Header().Set(RetryAfter, "60")
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte(http.ErrServerClosed.Error()))
return