README

graceful GoDoc Build Status Coverage Status Gitter

Graceful is a Go 1.3+ package enabling graceful shutdown of http.Handler servers.

Installation

To install, simply execute:

go get gopkg.in/tylerb/graceful.v1

I am using gopkg.in to control releases.

Usage

Using Graceful is easy. Simply create your http.Handler and pass it to the Run function:

package main

import (
  "gopkg.in/tylerb/graceful.v1"
  "net/http"
  "fmt"
  "time"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  graceful.Run(":3001",10*time.Second,mux)
}

Another example, using Negroni, functions in much the same manner:

package main

import (
  "github.com/codegangsta/negroni"
  "gopkg.in/tylerb/graceful.v1"
  "net/http"
  "fmt"
  "time"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic()
  n.UseHandler(mux)
  //n.Run(":3000")
  graceful.Run(":3001",10*time.Second,n)
}

In addition to Run there are the http.Server counterparts ListenAndServe, ListenAndServeTLS and Serve, which allow you to configure HTTPS, custom timeouts and error handling. Graceful may also be used by instantiating its Server type directly, which embeds an http.Server:

mux := // ...

srv := &graceful.Server{
  Timeout: 10 * time.Second,

  Server: &http.Server{
    Addr: ":1234",
    Handler: mux,
  },
}

srv.ListenAndServe()

This form allows you to set the ConnState callback, which works in the same way as in http.Server:

mux := // ...

srv := &graceful.Server{
  Timeout: 10 * time.Second,

  ConnState: func(conn net.Conn, state http.ConnState) {
    // conn has a new state
  },

  Server: &http.Server{
    Addr: ":1234",
    Handler: mux,
  },
}

srv.ListenAndServe()

Behaviour

When Graceful is sent a SIGINT or SIGTERM (possibly from ^C or a kill command), it:

  1. Disables keepalive connections.
  2. Closes the listening socket, allowing another process to listen on that port immediately.
  3. Starts a timer of timeout duration to give active requests a chance to finish.
  4. When timeout expires, closes all active connections.
  5. Closes the stopChan, waking up any blocking goroutines.
  6. Returns from the function, allowing the server to terminate.

Notes

If the timeout argument to Run is 0, the server never times out, allowing all active requests to complete.

If you wish to stop the server in some way other than an OS signal, you may call the Stop() function. This function stops the server, gracefully, using the new timeout value you provide. The StopChan() function returns a channel on which you can block while waiting for the server to stop. This channel will be closed when the server is stopped, allowing your execution to proceed. Multiple goroutines can block on this channel at the same time and all will be signalled when stopping is complete.

Important things to note when setting timeout to 0:

If you set the timeout to 0, it waits for all connections to the server to disconnect before shutting down. This means that even though requests over a connection have finished, it is possible for the client to hold the connection open and block the server from shutting down indefinitely.

This is especially evident when graceful is used to run HTTP/2 servers. Clients like Chrome and Firefox have been observed to hold onto the open connection indefinitely over HTTP/2, preventing the server from shutting down. In addition, there is also the risk of malicious clients holding and keeping the connection alive.

It is understandable that sometimes, you might want to wait for the client indefinitely because they might be uploading large files. In these type of cases, it is recommended that you set a reasonable timeout to kill the connection, and have the client perform resumable uploads. For example, the client can divide the file into chunks and reupload chunks that were in transit when the connection was terminated.

Contributing

If you would like to contribute, please:

  1. Create a GitHub issue regarding the contribution. Features and bugs should be discussed beforehand.
  2. Fork the repository.
  3. Create a pull request with your solution. This pull request should reference and close the issues (Fix #2).

All pull requests should:

  1. Pass gometalinter -t . with no warnings.
  2. Be go fmt formatted.
Expand ▾ Collapse ▴

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNotTCP = errors.New("only tcp connections have keepalive")

    ErrNotTCP indicates that network connection is not a TCP connection.

    Functions

    func DefaultLogger

    func DefaultLogger() *log.Logger

      DefaultLogger returns the logger used by Run, RunWithErr, ListenAndServe, ListenAndServeTLS and Serve. The logger outputs to STDERR by default.

      func LimitListener

      func LimitListener(l net.Listener, n int) net.Listener

        LimitListener returns a Listener that accepts at most n simultaneous connections from the provided Listener.

        func ListenAndServe

        func ListenAndServe(server *http.Server, timeout time.Duration) error

          ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.

          timeout is the duration to wait until killing active requests and stopping the server. If timeout is 0, the server never times out. It waits for all active requests to finish.

          func ListenAndServeTLS

          func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error

            ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.

            timeout is the duration to wait until killing active requests and stopping the server. If timeout is 0, the server never times out. It waits for all active requests to finish.

            func Run

            func Run(addr string, timeout time.Duration, n http.Handler)

              Run serves the http.Handler with graceful shutdown enabled.

              timeout is the duration to wait until killing active requests and stopping the server. If timeout is 0, the server never times out. It waits for all active requests to finish.

              func RunWithErr

              func RunWithErr(addr string, timeout time.Duration, n http.Handler) error

                RunWithErr is an alternative version of Run function which can return error.

                Unlike Run this version will not exit the program if an error is encountered but will return it instead.

                func Serve

                func Serve(server *http.Server, l net.Listener, timeout time.Duration) error

                  Serve is equivalent to http.Server.Serve with graceful shutdown enabled.

                  timeout is the duration to wait until killing active requests and stopping the server. If timeout is 0, the server never times out. It waits for all active requests to finish.

                  func TLSConfigHasHTTP2Enabled

                  func TLSConfigHasHTTP2Enabled(t *tls.Config) bool

                    TLSConfigHasHTTP2Enabled checks to see if a given TLS Config has http2 enabled.

                    Types

                    type Server

                    type Server struct {
                    	*http.Server
                    
                    	// Timeout is the duration to allow outstanding requests to survive
                    	// before forcefully terminating them.
                    	Timeout time.Duration
                    
                    	// Limit the number of outstanding requests
                    	ListenLimit int
                    
                    	// TCPKeepAlive sets the TCP keep-alive timeouts on accepted
                    	// connections. It prunes dead TCP connections ( e.g. closing
                    	// laptop mid-download)
                    	TCPKeepAlive time.Duration
                    
                    	// ConnState specifies an optional callback function that is
                    	// called when a client connection changes state. This is a proxy
                    	// to the underlying http.Server's ConnState, and the original
                    	// must not be set directly.
                    	ConnState func(net.Conn, http.ConnState)
                    
                    	// BeforeShutdown is an optional callback function that is called
                    	// before the listener is closed. Returns true if shutdown is allowed
                    	BeforeShutdown func() bool
                    
                    	// ShutdownInitiated is an optional callback function that is called
                    	// when shutdown is initiated. It can be used to notify the client
                    	// side of long lived connections (e.g. websockets) to reconnect.
                    	ShutdownInitiated func()
                    
                    	// NoSignalHandling prevents graceful from automatically shutting down
                    	// on SIGINT and SIGTERM. If set to true, you must shut down the server
                    	// manually with Stop().
                    	NoSignalHandling bool
                    
                    	// Logger used to notify of errors on startup and on stop.
                    	Logger *log.Logger
                    
                    	// LogFunc can be assigned with a logging function of your choice, allowing
                    	// you to use whatever logging approach you would like
                    	LogFunc func(format string, args ...interface{})
                    
                    	// Interrupted is true if the server is handling a SIGINT or SIGTERM
                    	// signal and is thus shutting down.
                    	Interrupted bool
                    	// contains filtered or unexported fields
                    }

                      Server wraps an http.Server with graceful connection handling. It may be used directly in the same way as http.Server, or may be constructed with the global functions in this package.

                      Example:

                      srv := &graceful.Server{
                      	Timeout: 5 * time.Second,
                      	Server: &http.Server{Addr: ":1234", Handler: handler},
                      }
                      srv.ListenAndServe()
                      

                      func (*Server) ListenAndServe

                      func (srv *Server) ListenAndServe() error

                        ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.

                        func (*Server) ListenAndServeTLS

                        func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error

                          ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.

                          func (*Server) ListenAndServeTLSConfig

                          func (srv *Server) ListenAndServeTLSConfig(config *tls.Config) error

                            ListenAndServeTLSConfig can be used with an existing TLS config and is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled,

                            func (*Server) ListenTLS

                            func (srv *Server) ListenTLS(certFile, keyFile string) (net.Listener, error)

                              ListenTLS is a convenience method that creates an https listener using the provided cert and key files. Use this method if you need access to the listener object directly. When ready, pass it to the Serve method.

                              func (*Server) Serve

                              func (srv *Server) Serve(listener net.Listener) error

                                Serve is equivalent to http.Server.Serve with graceful shutdown enabled.

                                func (*Server) Stop

                                func (srv *Server) Stop(timeout time.Duration)

                                  Stop instructs the type to halt operations and close the stop channel when it is finished.

                                  timeout is grace period for which to wait before shutting down the server. The timeout value passed here will override the timeout given when constructing the server, as this is an explicit command to stop the server.

                                  func (*Server) StopChan

                                  func (srv *Server) StopChan() <-chan struct{}

                                    StopChan gets the stop channel which will block until stopping has completed, at which point it is closed. Callers should never close the stop channel.

                                    Directories

                                    Path Synopsis