diff options
Diffstat (limited to 'service/container.go')
-rw-r--r-- | service/container.go | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/service/container.go b/service/container.go index 12c5a4a1..a003b7e3 100644 --- a/service/container.go +++ b/service/container.go @@ -7,20 +7,10 @@ import ( "sync" ) -// Config provides ability to slice configuration sections and unmarshal configuration data into -// given structure. -type Config interface { - // get nested config section (sub-map), returns nil if section not found. - Get(service string) Config - - // Unmarshal unmarshal config data into given struct. - Unmarshal(out interface{}) error -} - // Container controls all internal RR services and provides plugin based system. type Container interface { // Register add new service to the container under given name. - Register(name string, service Service) + Register(name string, service interface{}) // Reconfigure configures all underlying services with given configuration. Init(cfg Config) error @@ -30,7 +20,7 @@ type Container interface { // get returns svc instance by it's name or nil if svc not found. Method returns current service status // as second value. - Get(service string) (svc Service, status int) + Get(service string) (svc interface{}, status int) // Serve all configured services. Non blocking. Serve() error @@ -39,6 +29,36 @@ type Container interface { Stop() } +// Service can serve. Service can provide Init method which must return (bool, error) signature and might accept +// other services and/or configs as dependency. Container can be requested as well. Config can be requested in a form +// of service.Config or pointer to service specific config struct (automatically unmarshalled), config argument must +// implement service.HydrateConfig. +type Service interface { + // Serve serves. + Serve() error + + // Stop stops the service. + Stop() +} + +// Config provides ability to slice configuration sections and unmarshal configuration data into +// given structure. +type Config interface { + // get nested config section (sub-map), returns nil if section not found. + Get(service string) Config + + // Unmarshal unmarshal config data into given struct. + Unmarshal(out interface{}) error +} + +// HydrateConfig provides ability to automatically hydrate config with values using +// service.Config as the source. +type HydrateConfig interface { + // Hydrate must populate config values using given config source. + // Must return error if config is not valid. + Hydrate(cfg Config) error +} + type container struct { log logrus.FieldLogger mu sync.Mutex @@ -54,7 +74,7 @@ func NewContainer(log logrus.FieldLogger) Container { } // Register add new service to the container under given name. -func (c *container) Register(name string, service Service) { +func (c *container) Register(name string, service interface{}) { c.mu.Lock() defer c.mu.Unlock() @@ -82,7 +102,7 @@ func (c *container) Has(target string) bool { } // get returns svc instance by it's name or nil if svc not found. -func (c *container) Get(target string) (svc Service, status int) { +func (c *container) Get(target string) (svc interface{}, status int) { c.mu.Lock() defer c.mu.Unlock() @@ -98,27 +118,32 @@ func (c *container) Get(target string) (svc Service, status int) { // Init configures all underlying services with given configuration. func (c *container) Init(cfg Config) error { for _, e := range c.services { - if e.getStatus() >= StatusConfigured { + if e.getStatus() >= StatusOK { return fmt.Errorf("service [%s] has already been configured", e.name) } - segment := cfg.Get(e.name) - if segment == nil { - c.log.Debugf("[%s]: no config has been provided", e.name) - continue - } + // inject service dependencies (todo: move to container) + if ok, err := initService(e.svc, cfg.Get(e.name), c); err != nil { + if err == noConfig { + c.log.Warningf("[%s]: no config has been provided", e.name) + + // unable to meet dependency requirements, skippingF + continue + } - ok, err := e.svc.Init(segment, c) - if err != nil { return errors.Wrap(err, fmt.Sprintf("[%s]", e.name)) } else if ok { - e.setStatus(StatusConfigured) + e.setStatus(StatusOK) + c.log.Debugf("[%s]: initiated", e.name) + } else { + c.log.Debugf("[%s]: disabled", e.name) } } return nil } +//todo: refactor ???? // Serve all configured services. Non blocking. func (c *container) Serve() error { var ( @@ -127,7 +152,7 @@ func (c *container) Serve() error { ) for _, e := range c.services { - if e.hasStatus(StatusConfigured) { + if e.hasStatus(StatusOK) && e.canServe() { numServing++ } else { continue @@ -138,7 +163,7 @@ func (c *container) Serve() error { e.setStatus(StatusServing) defer e.setStatus(StatusStopped) - if err := e.svc.Serve(); err != nil { + if err := e.svc.(Service).Serve(); err != nil { c.log.Errorf("[%s]: %s", e.name, err) done <- errors.Wrap(err, fmt.Sprintf("[%s]", e.name)) } else { @@ -167,10 +192,12 @@ func (c *container) Serve() error { // Stop sends stop command to all running services. func (c *container) Stop() { + c.log.Debugf("received stop command") for _, e := range c.services { if e.hasStatus(StatusServing) { - e.svc.Stop() + e.svc.(Service).Stop() e.setStatus(StatusStopped) + c.log.Debugf("[%s]: stopped", e.name) } } |