diff options
author | Anton Titov <[email protected]> | 2019-12-23 12:04:12 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-23 12:04:12 +0300 |
commit | 7f694966730f6dac09d0d0ea3bf51276b8e4dfe4 (patch) | |
tree | 55d584785e87aef8ee15f5ab5f01c22d50754397 | |
parent | fadf373c1fe5e51bfaeb9e5ac3fe4ee748620a44 (diff) | |
parent | 028ff585f8f8a42f4796afdb932f97eee6eb8f4c (diff) |
Merge pull request #204 from spiral/feature/hotreload
[wip] Hot-reloading capabilities - review wanted
-rw-r--r-- | server_config.go | 40 | ||||
-rw-r--r-- | service/container.go | 13 | ||||
-rw-r--r-- | service/container_test.go | 14 | ||||
-rw-r--r-- | service/http/service.go | 7 | ||||
-rw-r--r-- | service/metrics/rpc_test.go | 5 | ||||
-rw-r--r-- | service/metrics/service.go | 2 |
6 files changed, 76 insertions, 5 deletions
diff --git a/server_config.go b/server_config.go index 35965962..5fb4a014 100644 --- a/server_config.go +++ b/server_config.go @@ -8,15 +8,22 @@ import ( "os" "os/exec" "strings" + "sync" "syscall" "time" ) +// CommandProducer can produce commands. +type CommandProducer func(cfg *ServerConfig) func() *exec.Cmd + // ServerConfig config combines factory, pool and cmd configurations. type ServerConfig struct { // Command includes command strings with all the parameters, example: "php worker.php pipes". Command string + // CommandProducer overwrites + CommandProducer CommandProducer + // Relay defines connection method and factory to be used to connect to workers: // "pipes", "tcp://:6001", "unix://rr.sock" // This config section must not change on re-configuration. @@ -31,7 +38,8 @@ type ServerConfig struct { Pool *Config // values defines set of values to be passed to the command context. - env []string + mu sync.Mutex + env map[string]string } // InitDefaults sets missing values to their default values. @@ -68,18 +76,42 @@ func (cfg *ServerConfig) Differs(new *ServerConfig) bool { // SetEnv sets new environment variable. Value is automatically uppercase-d. func (cfg *ServerConfig) SetEnv(k, v string) { - cfg.env = append(cfg.env, fmt.Sprintf("%s=%s", strings.ToUpper(k), v)) + cfg.mu.Lock() + defer cfg.mu.Unlock() + + if cfg.env == nil { + cfg.env = make(map[string]string) + } + + cfg.env[k] = v +} + +// GetEnv must return list of env variables. +func (cfg *ServerConfig) GetEnv() (env []string) { + env = append(os.Environ(), fmt.Sprintf("RR_RELAY=%s", cfg.Relay)) + for k, v := range cfg.env { + env = append(env, fmt.Sprintf("%s=%s", strings.ToUpper(k), v)) + } + + return } // makeCommands returns new command provider based on configured options. func (cfg *ServerConfig) makeCommand() func() *exec.Cmd { + cfg.mu.Lock() + defer cfg.mu.Unlock() + + if cfg.CommandProducer != nil { + return cfg.CommandProducer(cfg) + } + var cmd = strings.Split(cfg.Command, " ") return func() *exec.Cmd { cmd := exec.Command(cmd[0], cmd[1:]...) osutil.IsolateProcess(cmd) - cmd.Env = append(os.Environ(), fmt.Sprintf("RR_RELAY=%s", cfg.Relay)) - cmd.Env = append(cmd.Env, cfg.env...) + cmd.Env = cfg.GetEnv() + return cmd } } diff --git a/service/container.go b/service/container.go index a21b49b4..0be4f853 100644 --- a/service/container.go +++ b/service/container.go @@ -46,6 +46,9 @@ type Container interface { // Close all active services. Stop() + + // List service names. + List() []string } // Config provides ability to slice configuration sections and unmarshal configuration data into @@ -212,6 +215,16 @@ func (c *container) Stop() { } } +// List all service names. +func (c *container) List() []string { + names := make([]string, 0, len(c.services)) + for _, e := range c.services { + names = append(names, e.name) + } + + return names +} + // calls Init method with automatically resolved arguments. func (c *container) initService(s interface{}, segment Config) (bool, error) { r := reflect.TypeOf(s) diff --git a/service/container_test.go b/service/container_test.go index 8fcaede2..4628986a 100644 --- a/service/container_test.go +++ b/service/container_test.go @@ -129,6 +129,20 @@ func TestContainer_Has(t *testing.T) { assert.False(t, c.Has("another")) } +func TestContainer_List(t *testing.T) { + logger, hook := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := NewContainer(logger) + c.Register("test", &testService{}) + + assert.Equal(t, 0, len(hook.Entries)) + assert.Equal(t, 1, len(c.List())) + + assert.True(t, c.Has("test")) + assert.False(t, c.Has("another")) +} + func TestContainer_Get(t *testing.T) { logger, hook := test.NewNullLogger() logger.SetLevel(logrus.DebugLevel) diff --git a/service/http/service.go b/service/http/service.go index 58038acb..945a12c4 100644 --- a/service/http/service.go +++ b/service/http/service.go @@ -31,6 +31,7 @@ type middleware func(f http.HandlerFunc) http.HandlerFunc // Service manages rr, http servers. type Service struct { cfg *Config + cprod roadrunner.CommandProducer env env.Environment lsns []func(event int, ctx interface{}) mdwr []middleware @@ -48,6 +49,11 @@ func (s *Service) Attach(w roadrunner.Controller) { s.controller = w } +// ProduceCommands changes the default command generator method +func (s *Service) ProduceCommands(producer roadrunner.CommandProducer) { + s.cprod = producer +} + // AddMiddleware adds new net/http mdwr. func (s *Service) AddMiddleware(m middleware) { s.mdwr = append(s.mdwr, m) @@ -87,6 +93,7 @@ func (s *Service) Serve() error { } } + s.cfg.Workers.CommandProducer = s.cprod s.cfg.Workers.SetEnv("RR_HTTP", "true") s.rr = roadrunner.NewServer(s.cfg.Workers) diff --git a/service/metrics/rpc_test.go b/service/metrics/rpc_test.go index 6d061f1d..136f031c 100644 --- a/service/metrics/rpc_test.go +++ b/service/metrics/rpc_test.go @@ -43,10 +43,13 @@ func setup(t *testing.T, metric string, portNum string) (*rpc2.Client, service.C assert.True(t, s.(*Service).Enabled()) go func() { c.Serve() }() - time.Sleep(time.Millisecond * 100) + time.Sleep(time.Millisecond * 200) client, err := rs.Client() assert.NoError(t, err) + if err != nil { + panic(err) + } return client, c } diff --git a/service/metrics/service.go b/service/metrics/service.go index 4916b3e0..b581f041 100644 --- a/service/metrics/service.go +++ b/service/metrics/service.go @@ -1,5 +1,7 @@ package metrics +// todo: declare metric at runtime + import ( "context" "github.com/prometheus/client_golang/prometheus" |