summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2018-07-26 16:32:27 +0300
committerWolfy-J <[email protected]>2018-07-26 16:32:27 +0300
commitbcef5b36bb50b2fecd4db4ca8e01640347300bea (patch)
treeb6db6954063dd3288a80f24aa714e8799664d909 /service
parent0f8e2bab6888f1b27ed2bd1b91ac6b2677f03450 (diff)
- added support for custom env provider
- new config section "env" to share env variables with php process - container can resolve interfaces now
Diffstat (limited to 'service')
-rw-r--r--service/container.go57
-rw-r--r--service/env/config.go17
-rw-r--r--service/env/provider.go8
-rw-r--r--service/env/service.go21
-rw-r--r--service/http/attributes/attributes.go8
-rw-r--r--service/http/service.go27
6 files changed, 107 insertions, 31 deletions
diff --git a/service/container.go b/service/container.go
index 436d2e5f..3450a18c 100644
--- a/service/container.go
+++ b/service/container.go
@@ -8,7 +8,7 @@ import (
"sync"
)
-var noConfig = fmt.Errorf("no config has been provided")
+var errNoConfig = fmt.Errorf("no config has been provided")
// InitMethod contains name of the method to be automatically invoked while service initialization. Must return
// (bool, error). Container can be requested as well. Config can be requested in a form
@@ -132,7 +132,7 @@ func (c *container) Init(cfg Config) error {
// inject service dependencies
if ok, err := c.initService(e.svc, cfg.Get(e.name)); err != nil {
// soft error (skipping)
- if err == noConfig {
+ if err == errNoConfig {
c.log.Warningf("[%s]: no config has been provided", e.name)
continue
}
@@ -253,7 +253,7 @@ func (c *container) resolveValues(s interface{}, m reflect.Method, cfg Config) (
case v.Implements(reflect.TypeOf((*HydrateConfig)(nil)).Elem()): // injectable config
if cfg == nil {
- return nil, noConfig
+ return nil, errNoConfig
}
sc := reflect.New(v.Elem())
@@ -265,27 +265,18 @@ func (c *container) resolveValues(s interface{}, m reflect.Method, cfg Config) (
case v.Implements(reflect.TypeOf((*Config)(nil)).Elem()): // generic config section
if cfg == nil {
- return nil, noConfig
+ return nil, errNoConfig
}
values = append(values, reflect.ValueOf(cfg))
default: // dependency on other service (resolution to nil if service can't be found)
- found := false
- for _, e := range c.services {
- if !e.hasStatus(StatusOK) || !v.ConvertibleTo(reflect.ValueOf(e.svc).Type()) {
- continue
- }
-
- found = true
- values = append(values, reflect.ValueOf(e.svc))
- break
+ value, err := c.resolveValue(v)
+ if err != nil {
+ return nil, err
}
- if !found {
- // placeholder (make sure to check inside the method)
- values = append(values, reflect.New(v).Elem())
- }
+ values = append(values, value)
}
}
@@ -308,3 +299,35 @@ func (c *container) verifySignature(m reflect.Method) error {
return nil
}
+
+func (c *container) resolveValue(v reflect.Type) (reflect.Value, error) {
+ value := reflect.Value{}
+ for _, e := range c.services {
+ if !e.hasStatus(StatusOK) {
+ continue
+ }
+
+ if v.Kind() == reflect.Interface && reflect.TypeOf(e.svc).Implements(v) {
+ if value.IsValid() {
+ return value, fmt.Errorf("disambiguous dependency `%s`", v)
+ }
+
+ value = reflect.ValueOf(e.svc)
+ }
+
+ if v.ConvertibleTo(reflect.ValueOf(e.svc).Type()) {
+ if value.IsValid() {
+ return value, fmt.Errorf("disambiguous dependency `%s`", v)
+ }
+
+ value = reflect.ValueOf(e.svc)
+ }
+ }
+
+ if !value.IsValid() {
+ // placeholder (make sure to check inside the method)
+ value = reflect.New(v).Elem()
+ }
+
+ return value, nil
+}
diff --git a/service/env/config.go b/service/env/config.go
new file mode 100644
index 00000000..06342f98
--- /dev/null
+++ b/service/env/config.go
@@ -0,0 +1,17 @@
+package env
+
+import (
+ "github.com/spiral/roadrunner/service"
+)
+
+// Config defines set of env values for RR workers.
+type Config struct {
+ // Values to set as worker _ENV.
+ Values map[string]string
+}
+
+// Hydrate must populate Config values using given Config source. Must return error if Config is not valid.
+func (c *Config) Hydrate(cfg service.Config) error {
+ c.Values = map[string]string{"RR": "YES"}
+ return cfg.Unmarshal(&c.Values)
+}
diff --git a/service/env/provider.go b/service/env/provider.go
new file mode 100644
index 00000000..75a1e31b
--- /dev/null
+++ b/service/env/provider.go
@@ -0,0 +1,8 @@
+package env
+
+// Provider aggregates list of environment variables. This interface can be used in custom implementation to drive
+// values from external sources.
+type Provider interface {
+ // GetEnv must return list of env variables.
+ GetEnv() map[string]string
+}
diff --git a/service/env/service.go b/service/env/service.go
new file mode 100644
index 00000000..95e99093
--- /dev/null
+++ b/service/env/service.go
@@ -0,0 +1,21 @@
+package env
+
+// ID contains default svc name.
+const ID = "env"
+
+// Service provides ability to map _ENV values from config file.
+type Service struct {
+ cfg *Config
+}
+
+// Init must return configure svc and return true if svc hasStatus enabled. Must return error in case of
+// misconfiguration. Services must not be used without proper configuration pushed first.
+func (s *Service) Init(cfg *Config) (bool, error) {
+ s.cfg = cfg
+ return true, nil
+}
+
+// GetEnv must return list of env variables.
+func (s *Service) GetEnv() map[string]string {
+ return s.cfg.Values
+}
diff --git a/service/http/attributes/attributes.go b/service/http/attributes/attributes.go
index 94d0e9c1..77d6ea69 100644
--- a/service/http/attributes/attributes.go
+++ b/service/http/attributes/attributes.go
@@ -6,7 +6,9 @@ import (
"net/http"
)
-const contextKey = "psr:attributes"
+type attrKey int
+
+const contextKey attrKey = iota
type attrs map[string]interface{}
@@ -41,7 +43,7 @@ func All(r *http.Request) map[string]interface{} {
return v.(attrs)
}
-// get gets the value from request context. It replaces any existing
+// Get gets the value from request context. It replaces any existing
// values.
func Get(r *http.Request, key string) interface{} {
v := r.Context().Value(contextKey)
@@ -52,7 +54,7 @@ func Get(r *http.Request, key string) interface{} {
return v.(attrs).get(key)
}
-// set sets the key to value. It replaces any existing
+// Set sets the key to value. It replaces any existing
// values. Context specific.
func Set(r *http.Request, key string, value interface{}) error {
v := r.Context().Value(contextKey)
diff --git a/service/http/service.go b/service/http/service.go
index f7fdf2ab..a8f99669 100644
--- a/service/http/service.go
+++ b/service/http/service.go
@@ -3,6 +3,7 @@ package http
import (
"context"
"github.com/spiral/roadrunner"
+ "github.com/spiral/roadrunner/service/env"
"github.com/spiral/roadrunner/service/http/attributes"
"github.com/spiral/roadrunner/service/rpc"
"net/http"
@@ -18,10 +19,10 @@ type middleware func(f http.HandlerFunc) http.HandlerFunc
// Service manages rr, http servers.
type Service struct {
- cfg *Config
- lsns []func(event int, ctx interface{})
- mdws []middleware
-
+ cfg *Config
+ env env.Provider
+ lsns []func(event int, ctx interface{})
+ mdws []middleware
mu sync.Mutex
rr *roadrunner.Server
stopping int32
@@ -41,12 +42,13 @@ func (s *Service) AddListener(l func(event int, ctx interface{})) {
// Init must return configure svc and return true if svc hasStatus enabled. Must return error in case of
// misconfiguration. Services must not be used without proper configuration pushed first.
-func (s *Service) Init(cfg *Config, r *rpc.Service) (bool, error) {
+func (s *Service) Init(cfg *Config, r *rpc.Service, e env.Provider) (bool, error) {
if !cfg.Enable {
return false, nil
}
s.cfg = cfg
+ s.env = e
if r != nil {
r.Register(ID, &rpcServer{s})
}
@@ -57,6 +59,13 @@ func (s *Service) Init(cfg *Config, r *rpc.Service) (bool, error) {
// Serve serves the svc.
func (s *Service) Serve() error {
s.mu.Lock()
+
+ if s.env != nil {
+ for k, v := range s.env.GetEnv() {
+ s.cfg.Workers.SetEnv(k, v)
+ }
+ }
+
rr := roadrunner.NewServer(s.cfg.Workers)
s.rr = rr
@@ -116,11 +125,7 @@ func (s *Service) listener(event int, ctx interface{}) {
}
if event == roadrunner.EventServerFailure {
- if atomic.LoadInt32(&s.stopping) != 0 {
- // attempting rr server restart
- if err := s.rr.Start(); err != nil {
- s.Stop()
- }
- }
+ // underlying rr server is dead
+ s.Stop()
}
}