Skip to content

Commit

Permalink
Merge pull request #33 from spiral/feature/env-setter
Browse files Browse the repository at this point in the history
Feature/env setter
  • Loading branch information
wolfy-j authored Sep 10, 2018
2 parents ea97c18 + 46a06a4 commit a554a98
Show file tree
Hide file tree
Showing 22 changed files with 300 additions and 75 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
CHANGELOG
=========

v1.2.0 (10.09.2018)
-------
- added ability to request `*logrus.Logger`, `logrus.StdLogger`, `logrus.FieldLogger` dependency
in container
- added ability to set env values using `env.Enviroment`
- `env.Provider` renamed to `env.Enviroment`
- rr does not throw warning when service config is missing, instead debug level is used
- rr server config now support default value set (shorter configs)
- debug handlers has been moved from root command and now can be defined by each service
- bugfix: panic when using debug mode without http service registered
- `rr.Verbose` and `rr.Debug` are not public
- rpc service now exposes it's address to underlying workers to simplify the connection
- env service construction has been simplified in order to unify it with other services
- more tests

v1.1.1 (26.07.2018)
-------
- added support for custom env variables
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
cd $(dirname "${BASH_SOURCE[0]}")
OD="$(pwd)"
# Pushes application version into the build information.
RR_VERSION=1.1.1
RR_VERSION=1.2.0

# Hardcode some values to the core package
LDFLAGS="$LDFLAGS -X github.com/spiral/roadrunner/cmd/rr/cmd.Version=${RR_VERSION}"
Expand Down
36 changes: 17 additions & 19 deletions cmd/rr/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/spiral/roadrunner/cmd/rr/debug"
"github.com/spiral/roadrunner/cmd/rr/utils"
"github.com/spiral/roadrunner/service"
"github.com/spiral/roadrunner/service/http"
"os"
)

// Service bus for all the commands.
var (
cfgFile string
verbose, debugMode bool
cfgFile string

// Verbose enables verbosity mode (container specific).
Verbose bool

// Debug enables debug mode (service specific).
Debug bool

// Logger - shared logger.
Logger = logrus.New()
Expand Down Expand Up @@ -78,33 +81,28 @@ func (w *ViperWrapper) Unmarshal(out interface{}) error {
// Execute adds all child commands to the CLI command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the CLI.
func Execute() {
if cfg := initConfig(cfgFile, []string{"."}, ".rr"); cfg != nil {
if err := Container.Init(cfg); err != nil {
utils.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err)
os.Exit(1)
}
}

if err := CLI.Execute(); err != nil {
utils.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err)
os.Exit(1)
}
}

func init() {
CLI.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
CLI.PersistentFlags().BoolVarP(&debugMode, "debug", "d", false, "debug mode")
CLI.PersistentFlags().BoolVarP(&Verbose, "Verbose", "v", false, "Verbose output")
CLI.PersistentFlags().BoolVarP(&Debug, "debug", "d", false, "debug mode")
CLI.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is .rr.yaml)")

cobra.OnInitialize(func() {
if verbose {
if Verbose {
Logger.SetLevel(logrus.DebugLevel)
}

if debugMode {
svc, _ := Container.Get(http.ID)
svc.(*http.Service).AddListener(debug.Listener(Logger))
}

if cfg := initConfig(cfgFile, []string{"."}, ".rr"); cfg != nil {
if err := Container.Init(cfg); err != nil {
utils.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err)
os.Exit(1)
}
}
})
}

Expand Down
20 changes: 20 additions & 0 deletions cmd/rr/http/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package http

import (
rr "github.com/spiral/roadrunner/cmd/rr/cmd"

"github.com/spf13/cobra"
"github.com/spiral/roadrunner/cmd/rr/debug"
"github.com/spiral/roadrunner/service/http"
)

func init() {
cobra.OnInitialize(func() {
if rr.Debug {
svc, _ := rr.Container.Get(http.ID)
if svc, ok := svc.(*http.Service); ok {
svc.AddListener(debug.Listener(rr.Logger))
}
}
})
}
11 changes: 4 additions & 7 deletions cmd/rr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@
package main

import (
// colorful logging
"github.com/sirupsen/logrus"

rr "github.com/spiral/roadrunner/cmd/rr/cmd"

// services (plugins)
Expand All @@ -34,19 +32,18 @@ import (
"github.com/spiral/roadrunner/service/rpc"
"github.com/spiral/roadrunner/service/static"

// additional command handlers
// additional command and debug handlers
_ "github.com/spiral/roadrunner/cmd/rr/http"
)

func main() {
rr.Logger.Formatter = &logrus.TextFormatter{ForceColors: true}

rr.Container.Register(env.ID, env.NewService(map[string]string{"rr": rr.Version}))

rr.Container.Register(env.ID, &env.Service{})
rr.Container.Register(rpc.ID, &rpc.Service{})
rr.Container.Register(http.ID, &http.Service{})
rr.Container.Register(static.ID, &static.Service{})

rr.Logger.Formatter = &logrus.TextFormatter{ForceColors: true}

// you can register additional commands using cmd.CLI
rr.Execute()
}
7 changes: 4 additions & 3 deletions error_buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
)

const (
// EventStderrOutput - is triggered when worker sends data into stderr. The context is error message ([]byte).
// EventStderrOutput - is triggered when worker sends data into stderr. The context
// is error message ([]byte).
EventStderrOutput = 1900

// WaitDuration - for how long error buffer should attempt to aggregate error messages before merging output
// together since lastError update (required to keep error update together).
// WaitDuration - for how long error buffer should attempt to aggregate error messages
// before merging output together since lastError update (required to keep error update together).
WaitDuration = 100 * time.Millisecond
)

Expand Down
Empty file added git
Empty file.
38 changes: 38 additions & 0 deletions server_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,44 @@ type ServerConfig struct {
env []string
}

// SetDefaults sets missing values to their default values.
func (cfg *ServerConfig) SetDefaults() {
if cfg.Relay == "" {
cfg.Relay = "pipes"
}

if cfg.RelayTimeout == 0 {
cfg.RelayTimeout = time.Minute
}

if cfg.Pool == nil {
cfg.Pool = &Config{}
}

if cfg.Pool.AllocateTimeout == 0 {
cfg.Pool.AllocateTimeout = time.Minute
}

if cfg.Pool.DestroyTimeout == 0 {
cfg.Pool.DestroyTimeout = time.Minute
}
}

// UpscaleDurations converts duration values from nanoseconds to seconds.
func (cfg *ServerConfig) UpscaleDurations() {
if cfg.RelayTimeout < time.Microsecond {
cfg.RelayTimeout = time.Second * time.Duration(cfg.RelayTimeout.Nanoseconds())
}

if cfg.Pool.AllocateTimeout < time.Microsecond {
cfg.Pool.AllocateTimeout = time.Second * time.Duration(cfg.Pool.AllocateTimeout.Nanoseconds())
}

if cfg.Pool.DestroyTimeout < time.Microsecond {
cfg.Pool.DestroyTimeout = time.Second * time.Duration(cfg.Pool.DestroyTimeout.Nanoseconds())
}
}

// Differs returns true if configuration has changed but ignores pool or cmd changes.
func (cfg *ServerConfig) Differs(new *ServerConfig) bool {
return cfg.Relay != new.Relay || cfg.RelayTimeout != new.RelayTimeout
Expand Down
44 changes: 44 additions & 0 deletions server_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/stretchr/testify/assert"
"runtime"
"testing"
"time"
)

func Test_ServerConfig_PipeFactory(t *testing.T) {
Expand Down Expand Up @@ -90,3 +91,46 @@ func Test_ServerConfig_Cmd(t *testing.T) {
cmd := cfg.makeCommand()
assert.NotNil(t, cmd)
}

func Test_ServerConfig_SetEnv(t *testing.T) {
cfg := &ServerConfig{
Command: "php php-src/tests/client.php pipes",
}

cfg.SetEnv("key", "value")

cmd := cfg.makeCommand()
assert.NotNil(t, cmd)

c := cmd()

assert.Contains(t, c.Env, "KEY=value")
}

func Test_ServerConfigDefaults(t *testing.T) {
cfg := &ServerConfig{
Command: "php php-src/tests/client.php pipes",
}

cfg.SetDefaults()

assert.Equal(t, "pipes", cfg.Relay)
assert.Equal(t, time.Minute, cfg.Pool.AllocateTimeout)
assert.Equal(t, time.Minute, cfg.Pool.DestroyTimeout)
}

func Test_Config_Upscale(t *testing.T) {
cfg := &ServerConfig{
Command: "php php-src/tests/client.php pipes",
RelayTimeout: 1,
Pool: &Config{
AllocateTimeout: 1,
DestroyTimeout: 1,
},
}

cfg.UpscaleDurations()
assert.Equal(t, time.Second, cfg.RelayTimeout)
assert.Equal(t, time.Second, cfg.Pool.AllocateTimeout)
assert.Equal(t, time.Second, cfg.Pool.DestroyTimeout)
}
11 changes: 8 additions & 3 deletions service/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (c *container) Init(cfg Config) error {
if ok, err := c.initService(e.svc, cfg.Get(e.name)); err != nil {
// soft error (skipping)
if err == errNoConfig {
c.log.Warningf("[%s]: no config has been provided", e.name)
c.log.Debugf("[%s]: no config has been provided", e.name)
continue
}

Expand All @@ -152,7 +152,7 @@ func (c *container) Init(cfg Config) error {
// Serve all configured services. Non blocking.
func (c *container) Serve() error {
var (
numServing int
numServing = 0
done = make(chan interface{}, len(c.services))
)

Expand Down Expand Up @@ -213,7 +213,7 @@ func (c *container) Stop() {
func (c *container) initService(s interface{}, segment Config) (bool, error) {
r := reflect.TypeOf(s)

m, ok := r.MethodByName("Init")
m, ok := r.MethodByName(InitMethod)
if !ok {
// no Init method is presented, assuming service does not need initialization.
return true, nil
Expand Down Expand Up @@ -251,6 +251,11 @@ func (c *container) resolveValues(s interface{}, m reflect.Method, cfg Config) (
case v.Implements(reflect.TypeOf((*Container)(nil)).Elem()): // container
values = append(values, reflect.ValueOf(c))

case v.Implements(reflect.TypeOf((*logrus.StdLogger)(nil)).Elem()),
v.Implements(reflect.TypeOf((*logrus.FieldLogger)(nil)).Elem()),
v.ConvertibleTo(reflect.ValueOf(c.log).Type()): // logger
values = append(values, reflect.ValueOf(c.log))

case v.Implements(reflect.TypeOf((*HydrateConfig)(nil)).Elem()): // injectable config
if cfg == nil {
return nil, errNoConfig
Expand Down
5 changes: 4 additions & 1 deletion service/env/provider.go → service/env/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ 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 {
type Environment interface {
// GetEnv must return list of env variables.
GetEnv() (map[string]string, error)

// SetEnv sets or creates environment value.
SetEnv(key, value string)
}
23 changes: 17 additions & 6 deletions service/env/service.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package env

// ID contains default svc name.
const ID = "env"
const (
// ID contains default service name.
ID = "env"

// rrKey contains default env key to indicate than php running in RR mode.
rrKey = "rr"
)

// Service provides ability to map _ENV values from config file.
type Service struct {
Expand All @@ -12,16 +17,17 @@ type Service struct {
// NewService creates new env service instance for given rr version.
func NewService(defaults map[string]string) *Service {
s := &Service{values: defaults}
if s.values == nil {
s.values = make(map[string]string)
}

return s
}

// 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) {
if s.values == nil {
s.values = make(map[string]string)
s.values[rrKey] = "yes"
}

for k, v := range cfg.Values {
s.values[k] = v
}
Expand All @@ -33,3 +39,8 @@ func (s *Service) Init(cfg *Config) (bool, error) {
func (s *Service) GetEnv() (map[string]string, error) {
return s.values, nil
}

// SetEnv sets or creates environment value.
func (s *Service) SetEnv(key, value string) {
s.values[key] = value
}
Loading

0 comments on commit a554a98

Please sign in to comment.