mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-03 19:17:29 -05:00 
			
		
		
		
	Added a -grace flag to customize graceful shutdown period, fixed bugs related to closing file descriptors (and dup'ed fds), improved healthcheck signaling to parent, fixed a race condition with the graceful listener, etc. These improvements mainly provide better support for frequent reloading or unusual use cases of Start and Stop after a Restart (POSIX systems). This forum thread was valuable help in debugging: https://forum.golangbridge.org/t/bind-address-already-in-use-even-after-listener-closed/1510?u=matt
		
			
				
	
	
		
			77 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package server
 | 
						|
 | 
						|
import (
 | 
						|
	"net"
 | 
						|
	"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.Lock()
 | 
						|
		gl.stopped = true
 | 
						|
		gl.Unlock()
 | 
						|
		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
 | 
						|
	sync.Mutex                 // protects the stopped flag
 | 
						|
	httpWg     *sync.WaitGroup // pointer to the host's wg used for counting connections
 | 
						|
}
 | 
						|
 | 
						|
// Accept accepts a connection.
 | 
						|
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 {
 | 
						|
	gl.Lock()
 | 
						|
	if gl.stopped {
 | 
						|
		gl.Unlock()
 | 
						|
		return syscall.EINVAL
 | 
						|
	}
 | 
						|
	gl.Unlock()
 | 
						|
	gl.stop <- nil
 | 
						|
	return <-gl.stop
 | 
						|
}
 | 
						|
 | 
						|
// 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 {
 | 
						|
	err := c.Conn.Close()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// close can fail on http2 connections (as of Oct. 2015, before http2 in std lib)
 | 
						|
	// so don't decrement count unless close succeeds
 | 
						|
	c.httpWg.Done()
 | 
						|
	return nil
 | 
						|
}
 |