caddy/server/graceful.go
Matthew Holt b5b31e398c letsencrypt: Graceful restarts
Lots of refinement still needed and runs only on POSIX systems. Windows will not get true graceful restarts (for now), but we will opt for very, very quick forceful restarts. Also, server configs are no longer put into a map; it is critical that they stay ordered so that they can be matched with their sockets in the child process after forking.

This implementation of graceful restarts is probably not perfect, but it is a good start. Lots of details to attend to now.
2015-10-25 18:45:55 -06:00

71 lines
1.7 KiB
Go

package server
import (
"net"
"os"
"sync"
"syscall"
)
// newGracefulListener returns a gracefulListener that wraps l and
// uses wg (stored in the host server) to count connections.
func newGracefulListener(l ListenerFile, wg *sync.WaitGroup) *gracefulListener {
gl := &gracefulListener{ListenerFile: l, stop: make(chan error), httpWg: wg}
go func() {
<-gl.stop
gl.stopped = true
gl.stop <- gl.ListenerFile.Close()
}()
return gl
}
// gracefuListener is a net.Listener which can
// count the number of connections on it. Its
// methods mainly wrap net.Listener to be graceful.
type gracefulListener struct {
ListenerFile
stop chan error
stopped bool
httpWg *sync.WaitGroup // pointer to the host's wg used for counting connections
}
// Accept accepts a connection. This type wraps
func (gl *gracefulListener) Accept() (c net.Conn, err error) {
c, err = gl.ListenerFile.Accept()
if err != nil {
return
}
c = gracefulConn{Conn: c, httpWg: gl.httpWg}
gl.httpWg.Add(1)
return
}
// Close immediately closes the listener.
func (gl *gracefulListener) Close() error {
if gl.stopped {
return syscall.EINVAL
}
gl.stop <- nil
return <-gl.stop
}
// File implements ListenerFile; it gets the file of the listening socket.
func (gl *gracefulListener) File() (*os.File, error) {
return gl.ListenerFile.File()
}
// gracefulConn represents a connection on a
// gracefulListener so that we can keep track
// of the number of connections, thus facilitating
// a graceful shutdown.
type gracefulConn struct {
net.Conn
httpWg *sync.WaitGroup // pointer to the host server's connection waitgroup
}
// Close closes c's underlying connection while updating the wg count.
func (c gracefulConn) Close() error {
c.httpWg.Done()
return c.Conn.Close()
}