mirror of https://github.com/docker/docs.git
Subsystems can register cleanup handlers with Engine.OnShutdown
Signed-off-by: Solomon Hykes <solomon@docker.com>
This commit is contained in:
parent
93da07a8dc
commit
d745067487
|
@ -7,6 +7,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
@ -43,14 +45,18 @@ func unregister(name string) {
|
||||||
// It acts as a store for *containers*, and allows manipulation of these
|
// It acts as a store for *containers*, and allows manipulation of these
|
||||||
// containers by executing *jobs*.
|
// containers by executing *jobs*.
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
handlers map[string]Handler
|
handlers map[string]Handler
|
||||||
catchall Handler
|
catchall Handler
|
||||||
hack Hack // data for temporary hackery (see hack.go)
|
hack Hack // data for temporary hackery (see hack.go)
|
||||||
id string
|
id string
|
||||||
Stdout io.Writer
|
Stdout io.Writer
|
||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
Stdin io.Reader
|
Stdin io.Reader
|
||||||
Logging bool
|
Logging bool
|
||||||
|
tasks sync.WaitGroup
|
||||||
|
l sync.RWMutex // lock for shutdown
|
||||||
|
shutdown bool
|
||||||
|
onShutdown []func() // shutdown handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (eng *Engine) Register(name string, handler Handler) error {
|
func (eng *Engine) Register(name string, handler Handler) error {
|
||||||
|
@ -130,6 +136,68 @@ func (eng *Engine) Job(name string, args ...string) *Job {
|
||||||
return job
|
return job
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnShutdown registers a new callback to be called by Shutdown.
|
||||||
|
// This is typically used by services to perform cleanup.
|
||||||
|
func (eng *Engine) OnShutdown(h func()) {
|
||||||
|
eng.l.Lock()
|
||||||
|
eng.onShutdown = append(eng.onShutdown, h)
|
||||||
|
eng.l.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown permanently shuts down eng as follows:
|
||||||
|
// - It refuses all new jobs, permanently.
|
||||||
|
// - It waits for all active jobs to complete (with no timeout)
|
||||||
|
// - It calls all shutdown handlers concurrently (if any)
|
||||||
|
// - It returns when all handlers complete, or after 15 seconds,
|
||||||
|
// whichever happens first.
|
||||||
|
func (eng *Engine) Shutdown() {
|
||||||
|
eng.l.Lock()
|
||||||
|
if eng.shutdown {
|
||||||
|
eng.l.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
eng.shutdown = true
|
||||||
|
eng.l.Unlock()
|
||||||
|
// We don't need to protect the rest with a lock, to allow
|
||||||
|
// for other calls to immediately fail with "shutdown" instead
|
||||||
|
// of hanging for 15 seconds.
|
||||||
|
// This requires all concurrent calls to check for shutdown, otherwise
|
||||||
|
// it might cause a race.
|
||||||
|
|
||||||
|
// Wait for all jobs to complete
|
||||||
|
eng.tasks.Wait()
|
||||||
|
|
||||||
|
// Call shutdown handlers, if any.
|
||||||
|
// Timeout after 15 seconds.
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, h := range eng.onShutdown {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(h func()) {
|
||||||
|
defer wg.Done()
|
||||||
|
h()
|
||||||
|
}(h)
|
||||||
|
}
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second * 15):
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsShutdown returns true if the engine is in the process
|
||||||
|
// of shutting down, or already shut down.
|
||||||
|
// Otherwise it returns false.
|
||||||
|
func (eng *Engine) IsShutdown() bool {
|
||||||
|
eng.l.RLock()
|
||||||
|
defer eng.l.RUnlock()
|
||||||
|
return eng.shutdown
|
||||||
|
}
|
||||||
|
|
||||||
// ParseJob creates a new job from a text description using a shell-like syntax.
|
// ParseJob creates a new job from a text description using a shell-like syntax.
|
||||||
//
|
//
|
||||||
// The following syntax is used to parse `input`:
|
// The following syntax is used to parse `input`:
|
||||||
|
|
|
@ -47,6 +47,13 @@ const (
|
||||||
// If the job returns a failure status, an error is returned
|
// If the job returns a failure status, an error is returned
|
||||||
// which includes the status.
|
// which includes the status.
|
||||||
func (job *Job) Run() error {
|
func (job *Job) Run() error {
|
||||||
|
if job.Eng.IsShutdown() {
|
||||||
|
return fmt.Errorf("engine is shutdown")
|
||||||
|
}
|
||||||
|
job.Eng.l.Lock()
|
||||||
|
job.Eng.tasks.Add(1)
|
||||||
|
job.Eng.l.Unlock()
|
||||||
|
defer job.Eng.tasks.Done()
|
||||||
// FIXME: make this thread-safe
|
// FIXME: make this thread-safe
|
||||||
// FIXME: implement wait
|
// FIXME: implement wait
|
||||||
if !job.end.IsZero() {
|
if !job.end.IsZero() {
|
||||||
|
|
Loading…
Reference in New Issue