Skip to content

Commit

Permalink
Close new connections after 5s in closeIdleConns
Browse files Browse the repository at this point in the history
When calling closeIdleConns() also close new connections that haven't
received any data within 5 seconds.
Some applications open new connections but don't send anything and keep
them as keep-alive for potential future requests. We don't want to
keeping hanging on these when shutting down a server.
  • Loading branch information
erikdubbelboer authored and bbenzikry committed Sep 11, 2022
1 parent 0ac90c1 commit dbc2733
Showing 1 changed file with 18 additions and 8 deletions.
26 changes: 18 additions & 8 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ type Server struct {
// We need to know our listeners and idle connections so we can close them in Shutdown().
ln []net.Listener

idleConns map[net.Conn]struct{}
idleConns map[net.Conn]time.Time
idleConnsMu sync.Mutex

mu sync.Mutex
Expand Down Expand Up @@ -1839,12 +1839,12 @@ func (s *Server) Shutdown() error {
close(s.done)
}

s.closeIdleConns()

// Closing the listener will make Serve() call Stop on the worker pool.
// Setting .stop to 1 will make serveConn() break out of its loop.
// Now we just have to wait until all workers are done.
for {
s.closeIdleConns()

if open := atomic.LoadInt32(&s.open); open == 0 {
break
}
Expand Down Expand Up @@ -2816,9 +2816,16 @@ func (s *Server) trackConn(c net.Conn, state ConnState) {
switch state {
case StateIdle:
if s.idleConns == nil {
s.idleConns = make(map[net.Conn]struct{})
s.idleConns = make(map[net.Conn]time.Time)
}
s.idleConns[c] = struct{}{}
s.idleConns[c] = time.Now()
case StateNew:
if s.idleConns == nil {
s.idleConns = make(map[net.Conn]time.Time)
}
// Count the connection as Idle after 5 seconds.
// Same as net/http.Server: https://github.com/golang/go/blob/85d7bab91d9a3ed1f76842e4328973ea75efef54/src/net/http/server.go#L2834-L2836
s.idleConns[c] = time.Now().Add(time.Second * 5)

default:
delete(s.idleConns, c)
Expand All @@ -2828,10 +2835,13 @@ func (s *Server) trackConn(c net.Conn, state ConnState) {

func (s *Server) closeIdleConns() {
s.idleConnsMu.Lock()
for c := range s.idleConns {
_ = c.Close()
now := time.Now()
for c, t := range s.idleConns {
if now.Sub(t) >= 0 {
_ = c.Close()
delete(s.idleConns, c)
}
}
s.idleConns = nil
s.idleConnsMu.Unlock()
}

Expand Down

0 comments on commit dbc2733

Please sign in to comment.