summaryrefslogtreecommitdiff
path: root/service/container.go
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2018-07-08 13:06:05 -0700
committerWolfy-J <[email protected]>2018-07-08 13:06:05 -0700
commit29c9bf94350e86ec96f5ce5eeb476dfcd57302cd (patch)
tree9f59af6446958d144b7de91b5005a3727dc90661 /service/container.go
parent3c3a7801100f29c99a5e446646c818bf16ccd5f0 (diff)
dependency injection and lighter service Init methods.
Diffstat (limited to 'service/container.go')
-rw-r--r--service/container.go79
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)
}
}