net/http: add built-in graceful shutdown support to Server

by patrick.allen.higgins:

http.Server only offers flavors of Serve() without a way to shut them down. Closing the
listener should make the server stop, but there seems to be a race in TLS servers where
this does not always work.

Further, in-progress requests cannot complete before exiting without some kind of
wrapper for net.Listener and net.Conn which includes synchronization between
Listener.Accept() and Conn.Close().

See https://groups.google.com/d/topic/golang-nuts/i4_kPK-rVxI/discussion for some
details.

A use-case for this is zero-downtime restarts: a master process opens a listener and
then spawns a slave, passing it the listener. When the master receives a SIGHUP, it
spawns a new slave. When the slave starts servicing requests, it signals the master and
the master signals the old slave to shutdown. The old slave must shutdown gracefully to
prevent service interruption.

3 thoughts on “net/http: add built-in graceful shutdown support to Server

  1. Comment 22:

    Status update: Go 1.3 will have all the necessary net/http changes (Server.ConnState and
    Server.SetKeepAlivesEnabled) for other people to implement graceful shutdown properly,
    outside the net/http package.
    But because there are various policy questions of how quickly and how politely to shut
    down a server, we're going to refrain from unilaterally making that policy decision now
    (in the form of e.g. a Server.Close method) and instead make people pick their own
    policy for now.
    It's possible in the future (after some experience using different shutdown strategies
    in Go 1.3) we might see the common patterns and add a convenience shutdown/close method,
    perhaps with a timeout or options, once we know what the set of options are.
    So punting this to Go 1.4, even though most of the work will already be in Go 1.3.

    Labels changed: added release-go1.4, removed release-go1.3maybe.

  2. No, but I think a plan has started to form. It’ll be a blocking:

    func (s *Server) Shutdown(context.Context) error {}
    func (s *Server) Close() error {}

    Where the first one is graceful and takes a context (so you can abort early if it’s taking too long), and the second one is forced and immediate. It would only return an error to fit the normal io.Closer signature, but would basically always return nil, even if it broke a bunch of in-use connections.

    The Go 1.8 dev tree closes Sunday night, so I’ll mark this as Go 1.9.

  3. I managed to implement this in a few hours before the freeze, and people have been wanting this forever, so Go 1.8 it is.