Codebase list golang-github-zenazn-goji / run/320db3f7-236d-4be4-b1f5-2a2fdc596d69/main graceful / graceful.go
run/320db3f7-236d-4be4-b1f5-2a2fdc596d69/main

Tree @run/320db3f7-236d-4be4-b1f5-2a2fdc596d69/main (Download .tar.gz)

graceful.go @run/320db3f7-236d-4be4-b1f5-2a2fdc596d69/mainraw · history · blame

/*
Package graceful implements graceful shutdown for HTTP servers by closing idle
connections after receiving a signal. By default, this package listens for
interrupts (i.e., SIGINT), but when it detects that it is running under Einhorn
it will additionally listen for SIGUSR2 as well, giving your application
automatic support for graceful restarts/code upgrades.
*/
package graceful

import (
	"net"
	"sync/atomic"

	"github.com/zenazn/goji/graceful/listener"
)

// WrapListener wraps an arbitrary net.Listener for use with graceful shutdowns.
// In the background, it uses the listener sub-package to Wrap the listener in
// Deadline mode. If another mode of operation is desired, you should call
// listener.Wrap yourself: this function is smart enough to not double-wrap
// listeners.
func WrapListener(l net.Listener) net.Listener {
	if lt, ok := l.(*listener.T); ok {
		appendListener(lt)
		return lt
	}

	lt := listener.Wrap(l, listener.Deadline)
	appendListener(lt)
	return lt
}

func appendListener(l *listener.T) {
	mu.Lock()
	defer mu.Unlock()

	listeners = append(listeners, l)
}

const errClosing = "use of closed network connection"

// During graceful shutdown, calls to Accept will start returning errors. This
// is inconvenient, since we know these sorts of errors are peaceful, so we
// silently swallow them.
func peacefulError(err error) error {
	if atomic.LoadInt32(&closing) == 0 {
		return err
	}
	// Unfortunately Go doesn't really give us a better way to select errors
	// than this, so *shrug*.
	if oe, ok := err.(*net.OpError); ok {
		switch oe.Op {
		// backward compatibility: older golang returns AcceptEx on Windows.
		// Current golang returns "accept" consistently. It's platform independent.
		// See https://github.com/golang/go/commit/b0f4ee533a875c258ac1030ee382f0ffe2de304b
		case "AcceptEx":
			fallthrough
		case "accept":
			if oe.Err.Error() == errClosing {
				return nil
			}
		}
	}
	return err
}