Improve and clean up modules package to also consider dependencies in prepping phase

This commit is contained in:
Daniel 2019-03-12 22:56:23 +01:00
parent 3188134203
commit d6ef9a62f2
4 changed files with 283 additions and 180 deletions

View file

@ -4,15 +4,15 @@ package modules
import (
"errors"
"fmt"
"sync"
"github.com/tevino/abool"
)
var (
modulesLock sync.Mutex
modules = make(map[string]*Module)
modulesOrder []*Module
modulesLock sync.Mutex
modules = make(map[string]*Module)
// ErrCleanExit is returned by Start() when the program is interrupted before starting. This can happen for example, when using the "--help" flag.
ErrCleanExit = errors.New("clean exit requested")
@ -21,14 +21,18 @@ var (
// Module represents a module.
type Module struct {
Name string
Active *abool.AtomicBool
Prepped *abool.AtomicBool
Started *abool.AtomicBool
Stopped *abool.AtomicBool
inTransition *abool.AtomicBool
prep func() error
start func() error
stop func() error
dependencies []string
depNames []string
depModules []*Module
depReverse []*Module
}
func dummyAction() error {
@ -39,12 +43,14 @@ func dummyAction() error {
func Register(name string, prep, start, stop func() error, dependencies ...string) *Module {
newModule := &Module{
Name: name,
Active: abool.NewBool(false),
Prepped: abool.NewBool(false),
Started: abool.NewBool(false),
Stopped: abool.NewBool(false),
inTransition: abool.NewBool(false),
prep: prep,
start: start,
stop: stop,
dependencies: dependencies,
depNames: dependencies,
}
// replace nil arguments with dummy action
@ -60,7 +66,72 @@ func Register(name string, prep, start, stop func() error, dependencies ...strin
modulesLock.Lock()
defer modulesLock.Unlock()
modulesOrder = append(modulesOrder, newModule)
modules[name] = newModule
return newModule
}
func initDependencies() error {
for _, m := range modules {
for _, depName := range m.depNames {
// get dependency
depModule, ok := modules[depName]
if !ok {
return fmt.Errorf("modules: module %s declares dependency \"%s\", but this module has not been registered", m.Name, depName)
}
// link together
m.depModules = append(m.depModules, depModule)
depModule.depReverse = append(depModule.depReverse, m)
}
}
return nil
}
// ReadyToPrep returns whether all dependencies are ready for this module to prep.
func (m *Module) ReadyToPrep() bool {
if m.inTransition.IsSet() || m.Prepped.IsSet() {
return false
}
for _, dep := range m.depModules {
if !dep.Prepped.IsSet() {
return false
}
}
return true
}
// ReadyToStart returns whether all dependencies are ready for this module to start.
func (m *Module) ReadyToStart() bool {
if m.inTransition.IsSet() || m.Started.IsSet() {
return false
}
for _, dep := range m.depModules {
if !dep.Started.IsSet() {
return false
}
}
return true
}
// ReadyToStop returns whether all dependencies are ready for this module to stop.
func (m *Module) ReadyToStop() bool {
if !m.Started.IsSet() || m.inTransition.IsSet() || m.Stopped.IsSet() {
return false
}
for _, revDep := range m.depReverse {
// not ready if a reverse dependency was started, but not yet stopped
if revDep.Started.IsSet() && !revDep.Stopped.IsSet() {
return false
}
}
return true
}