pip compatible server to serve Python packages out of GitHub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

118 lines
2.8 KiB

package graceful
import (
"os"
"os/signal"
"sync"
"sync/atomic"
"github.com/zenazn/goji/graceful/listener"
)
var mu sync.Mutex // protects everything that follows
var listeners = make([]*listener.T, 0)
var prehooks = make([]func(), 0)
var posthooks = make([]func(), 0)
var closing int32
var wait = make(chan struct{})
var stdSignals = []os.Signal{os.Interrupt}
var sigchan = make(chan os.Signal, 1)
func init() {
go waitForSignal()
}
// HandleSignals installs signal handlers for a set of standard signals. By
// default, this set only includes keyboard interrupts, however when the package
// detects that it is running under Einhorn, a SIGUSR2 handler is installed as
// well.
func HandleSignals() {
AddSignal(stdSignals...)
}
// AddSignal adds the given signal to the set of signals that trigger a graceful
// shutdown.
func AddSignal(sig ...os.Signal) {
signal.Notify(sigchan, sig...)
}
// ResetSignals resets the list of signals that trigger a graceful shutdown.
func ResetSignals() {
signal.Stop(sigchan)
}
type userShutdown struct{}
func (u userShutdown) String() string {
return "application initiated shutdown"
}
func (u userShutdown) Signal() {}
// Shutdown manually triggers a shutdown from your application. Like Wait(),
// blocks until all connections have gracefully shut down.
func Shutdown() {
sigchan <- userShutdown{}
<-wait
}
// PreHook registers a function to be called before any of this package's normal
// shutdown actions. All listeners will be called in the order they were added,
// from a single goroutine.
func PreHook(f func()) {
mu.Lock()
defer mu.Unlock()
prehooks = append(prehooks, f)
}
// PostHook registers a function to be called after all of this package's normal
// shutdown actions. All listeners will be called in the order they were added,
// from a single goroutine, and are guaranteed to be called after all listening
// connections have been closed, but before Wait() returns.
//
// If you've Hijacked any connections that must be gracefully shut down in some
// other way (since this library disowns all hijacked connections), it's
// reasonable to use a PostHook to signal and wait for them.
func PostHook(f func()) {
mu.Lock()
defer mu.Unlock()
posthooks = append(posthooks, f)
}
func waitForSignal() {
<-sigchan
mu.Lock()
defer mu.Unlock()
for _, f := range prehooks {
f()
}
atomic.StoreInt32(&closing, 1)
var wg sync.WaitGroup
wg.Add(len(listeners))
for _, l := range listeners {
go func(l *listener.T) {
defer wg.Done()
l.Close()
l.Drain()
}(l)
}
wg.Wait()
for _, f := range posthooks {
f()
}
close(wait)
}
// Wait for all connections to gracefully shut down. This is commonly called at
// the bottom of the main() function to prevent the program from exiting
// prematurely.
func Wait() {
<-wait
}