diff options
85 files changed, 349 insertions, 203 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04208eeb..8f4dc73b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,17 +130,19 @@ jobs: file: ./coverage-ci/summary.txt fail_ci_if_error: false - golangci-check: + + golangci-lint: name: Golang-CI (lint) - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v1 + uses: actions/checkout@v2 - - name: golangci-lint - uses: reviewdog/action-golangci-lint@v1 # action page: <https://github.com/reviewdog/action-golangci-lint> + - name: Run linter + uses: golangci/golangci-lint-action@v2 # Action page: <https://github.com/golangci/golangci-lint-action> with: - github_token: ${{ secrets.github_token }} + version: v1.35 # without patch version + only-new-issues: false # show only new issues if it's a pull request image: name: Build docker image @@ -41,22 +41,23 @@ metrics: http: # http host to listen. address: 0.0.0.0:8080 + # override http error code for the application errors (default 500) + appErrorCode: 505 + # override http error code for the internal RR errors (default 500) + internalErrorCode: 505 ssl: # custom https port (default 443) - port: 443 - + port: 443 # force redirect to https connection redirect: true - # ssl cert - cert: server.crt - + cert: server.crt # ssl private key - key: server.key - + key: server.key # rootCA certificate - rootCa: root.crt + rootCa: root.crt + # HTTP service provides FastCGI as frontend fcgi: @@ -17,6 +17,6 @@ status = [ 'Build docker image', ] -required_approvals = 1 +required_approvals = 0 delete_merged_branches = true timeout-sec = 1800 diff --git a/cmd/rr/cmd/root.go b/cmd/rr/cmd/root.go index e67a4e62..13d74d25 100644 --- a/cmd/rr/cmd/root.go +++ b/cmd/rr/cmd/root.go @@ -21,15 +21,16 @@ package cmd import ( + "log" + "net/http" + "net/http/pprof" + "os" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spiral/roadrunner/cmd/util" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/limit" - "log" - "net/http" - "net/http/pprof" - "os" ) // Services bus for all the commands. diff --git a/cmd/rr/cmd/serve.go b/cmd/rr/cmd/serve.go index cafbdd4f..70682780 100644 --- a/cmd/rr/cmd/serve.go +++ b/cmd/rr/cmd/serve.go @@ -21,11 +21,12 @@ package cmd import ( - "github.com/spf13/cobra" "os" "os/signal" "sync" "syscall" + + "github.com/spf13/cobra" ) func init() { diff --git a/cmd/rr/http/debug.go b/cmd/rr/http/debug.go index ae383e8d..02023e36 100644 --- a/cmd/rr/http/debug.go +++ b/cmd/rr/http/debug.go @@ -2,16 +2,17 @@ package http import ( "fmt" + "net" + "net/http" + "strings" + "time" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spiral/roadrunner" rr "github.com/spiral/roadrunner/cmd/rr/cmd" "github.com/spiral/roadrunner/cmd/util" rrhttp "github.com/spiral/roadrunner/service/http" - "net" - "net/http" - "strings" - "time" ) func init() { diff --git a/cmd/rr/http/metrics.go b/cmd/rr/http/metrics.go index 21bbbaf1..6aad560e 100644 --- a/cmd/rr/http/metrics.go +++ b/cmd/rr/http/metrics.go @@ -1,14 +1,15 @@ package http import ( + "strconv" + "time" + "github.com/prometheus/client_golang/prometheus" "github.com/spf13/cobra" rr "github.com/spiral/roadrunner/cmd/rr/cmd" rrhttp "github.com/spiral/roadrunner/service/http" "github.com/spiral/roadrunner/service/metrics" "github.com/spiral/roadrunner/util" - "strconv" - "time" ) func init() { diff --git a/cmd/rr/http/workers.go b/cmd/rr/http/workers.go index 4444b87f..be6d4038 100644 --- a/cmd/rr/http/workers.go +++ b/cmd/rr/http/workers.go @@ -21,16 +21,17 @@ package http import ( - tm "github.com/buger/goterm" - "github.com/spf13/cobra" - rr "github.com/spiral/roadrunner/cmd/rr/cmd" - "github.com/spiral/roadrunner/cmd/util" - "github.com/spiral/roadrunner/service/http" "net/rpc" "os" "os/signal" "syscall" "time" + + tm "github.com/buger/goterm" + "github.com/spf13/cobra" + rr "github.com/spiral/roadrunner/cmd/rr/cmd" + "github.com/spiral/roadrunner/cmd/util" + "github.com/spiral/roadrunner/service/http" ) var ( diff --git a/cmd/util/config.go b/cmd/util/config.go index 08e01a89..674260a8 100644 --- a/cmd/util/config.go +++ b/cmd/util/config.go @@ -3,11 +3,12 @@ package util import ( "bytes" "fmt" - "github.com/spf13/viper" - "github.com/spiral/roadrunner/service" "os" "path/filepath" "strings" + + "github.com/spf13/viper" + "github.com/spiral/roadrunner/service" ) // ConfigWrapper provides interface bridge between v configs and service.Config. diff --git a/cmd/util/cprint.go b/cmd/util/cprint.go index 3a986fd6..37cb0bc5 100644 --- a/cmd/util/cprint.go +++ b/cmd/util/cprint.go @@ -2,10 +2,11 @@ package util import ( "fmt" - "github.com/mgutz/ansi" "os" "regexp" "strings" + + "github.com/mgutz/ansi" ) var ( diff --git a/cmd/util/debug.go b/cmd/util/debug.go index 9b94510d..c5cf68bb 100644 --- a/cmd/util/debug.go +++ b/cmd/util/debug.go @@ -1,9 +1,10 @@ package util import ( + "strings" + "github.com/sirupsen/logrus" "github.com/spiral/roadrunner" - "strings" ) // LogEvent outputs rr event into given logger and return false if event was not handled. diff --git a/cmd/util/rpc.go b/cmd/util/rpc.go index 8ff6720a..cb88943e 100644 --- a/cmd/util/rpc.go +++ b/cmd/util/rpc.go @@ -2,9 +2,10 @@ package util import ( "errors" + "net/rpc" + "github.com/spiral/roadrunner/service" rrpc "github.com/spiral/roadrunner/service/rpc" - "net/rpc" ) // RPCClient returns RPC client associated with given rr service container. diff --git a/cmd/util/table.go b/cmd/util/table.go index c0e20837..4f76be2c 100644 --- a/cmd/util/table.go +++ b/cmd/util/table.go @@ -1,12 +1,13 @@ package util import ( - "github.com/dustin/go-humanize" - "github.com/olekukonko/tablewriter" - rrutil "github.com/spiral/roadrunner/util" "os" "strconv" "time" + + "github.com/dustin/go-humanize" + "github.com/olekukonko/tablewriter" + rrutil "github.com/spiral/roadrunner/util" ) // WorkerTable renders table with information about rr server workers. @@ -8,6 +8,9 @@ import ( // Config defines basic behaviour of worker creation and handling process. type Config struct { + // Error code for pool errors in the http handler (default 500) + PoolErrorCode uint64 + // NumWorkers defines how many sub-processes can be run at once. This value // might be doubled by Swapper while hot-swap. NumWorkers int64 diff --git a/config_test.go b/config_test.go index e51cb2c4..41e2059d 100644 --- a/config_test.go +++ b/config_test.go @@ -1,9 +1,10 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/stretchr/testify/assert" ) func Test_NumWorkers(t *testing.T) { diff --git a/controller.go b/controller.go index 020ea4dd..2079f052 100644 --- a/controller.go +++ b/controller.go @@ -13,4 +13,4 @@ type Controller interface { type Attacher interface { // Attach attaches controller to the service. Attach(c Controller) -}
\ No newline at end of file +} diff --git a/controller_test.go b/controller_test.go index d177feda..75b4d33e 100644 --- a/controller_test.go +++ b/controller_test.go @@ -2,10 +2,11 @@ package roadrunner import ( "fmt" - "github.com/stretchr/testify/assert" "runtime" "testing" "time" + + "github.com/stretchr/testify/assert" ) type eWatcher struct { diff --git a/error_buffer_test.go b/error_buffer_test.go index c163ea43..c112159f 100644 --- a/error_buffer_test.go +++ b/error_buffer_test.go @@ -1,8 +1,9 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestErrBuffer_Write_Len(t *testing.T) { diff --git a/errors_test.go b/errors_test.go index 6bb650af..75a86840 100644 --- a/errors_test.go +++ b/errors_test.go @@ -2,8 +2,9 @@ package roadrunner import ( "errors" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func Test_JobError_Error(t *testing.T) { diff --git a/osutil/isolate_win.go b/osutil/isolate_win.go index 52fb5d8a..bac0a35e 100644 --- a/osutil/isolate_win.go +++ b/osutil/isolate_win.go @@ -14,4 +14,4 @@ func IsolateProcess(cmd *exec.Cmd) { func ExecuteFromUser(cmd *exec.Cmd, u string) error { return nil -}
\ No newline at end of file +} diff --git a/pipe_factory_test.go b/pipe_factory_test.go index 14cf1272..378cb637 100644 --- a/pipe_factory_test.go +++ b/pipe_factory_test.go @@ -1,10 +1,11 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "os/exec" "testing" "time" + + "github.com/stretchr/testify/assert" ) func Test_Pipe_Start(t *testing.T) { diff --git a/protocol.go b/protocol.go index b00eb2a4..486f1055 100644 --- a/protocol.go +++ b/protocol.go @@ -2,9 +2,10 @@ package roadrunner import ( "fmt" + "os" + json "github.com/json-iterator/go" "github.com/spiral/goridge/v2" - "os" ) type stopCommand struct { diff --git a/protocol_test.go b/protocol_test.go index 55c603a5..f17ffe79 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -1,10 +1,11 @@ package roadrunner import ( + "testing" + "github.com/pkg/errors" "github.com/spiral/goridge/v2" "github.com/stretchr/testify/assert" - "testing" ) type relayMock struct { @@ -1,9 +1,9 @@ package roadrunner import ( - "fmt" - "github.com/pkg/errors" "sync" + + "github.com/pkg/errors" ) const ( @@ -133,11 +133,13 @@ func (s *Server) Stop() { s.throw(EventServerStop, s) } +var ErrNoAssociatedPool = errors.New("no associared pool") + // Exec one task with given payload and context, returns result or error. func (s *Server) Exec(rqs *Payload) (rsp *Payload, err error) { pool := s.Pool() if pool == nil { - return nil, fmt.Errorf("no associared pool") + return nil, ErrNoAssociatedPool } return pool.Exec(rqs) diff --git a/server_config.go b/server_config.go index 32ff0ebc..ea4da8dd 100644 --- a/server_config.go +++ b/server_config.go @@ -3,7 +3,6 @@ package roadrunner import ( "errors" "fmt" - "github.com/spiral/roadrunner/osutil" "net" "os" "os/exec" @@ -11,6 +10,8 @@ import ( "sync" "syscall" "time" + + "github.com/spiral/roadrunner/osutil" ) // CommandProducer can produce commands. diff --git a/server_config_test.go b/server_config_test.go index c88f9082..4dae7550 100644 --- a/server_config_test.go +++ b/server_config_test.go @@ -1,9 +1,10 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/stretchr/testify/assert" ) func Test_ServerConfig_PipeFactory(t *testing.T) { diff --git a/server_test.go b/server_test.go index 9ab480b1..a8d52856 100644 --- a/server_test.go +++ b/server_test.go @@ -1,11 +1,12 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "os/exec" "runtime" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestServer_PipesEcho(t *testing.T) { diff --git a/service/container.go b/service/container.go index 77a6dfc0..49eea733 100644 --- a/service/container.go +++ b/service/container.go @@ -2,10 +2,11 @@ package service import ( "fmt" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" "reflect" "sync" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) var errNoConfig = fmt.Errorf("no config has been provided") diff --git a/service/container_test.go b/service/container_test.go index b3ec7054..f990b2cb 100644 --- a/service/container_test.go +++ b/service/container_test.go @@ -2,13 +2,14 @@ package service import ( "errors" + "sync" + "testing" + "time" + json "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" - "sync" - "testing" - "time" ) type testService struct { diff --git a/service/entry_test.go b/service/entry_test.go index b5c71a10..5ca9c338 100644 --- a/service/entry_test.go +++ b/service/entry_test.go @@ -1,8 +1,9 @@ package service import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestEntry_CanServeFalse(t *testing.T) { diff --git a/service/env/config_test.go b/service/env/config_test.go index a526990d..cc2bdf97 100644 --- a/service/env/config_test.go +++ b/service/env/config_test.go @@ -1,15 +1,16 @@ package env import ( + "testing" + json "github.com/json-iterator/go" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" - "testing" ) type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { j := json.ConfigCompatibleWithStandardLibrary return j.Unmarshal([]byte(cfg.cfg), out) diff --git a/service/env/service_test.go b/service/env/service_test.go index 19cc03c7..a354214c 100644 --- a/service/env/service_test.go +++ b/service/env/service_test.go @@ -1,8 +1,9 @@ package env import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func Test_NewService(t *testing.T) { diff --git a/service/gzip/config_test.go b/service/gzip/config_test.go index c2168166..8d03aecf 100644 --- a/service/gzip/config_test.go +++ b/service/gzip/config_test.go @@ -1,15 +1,16 @@ package gzip import ( + "testing" + json "github.com/json-iterator/go" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" - "testing" ) type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { j := json.ConfigCompatibleWithStandardLibrary return j.Unmarshal([]byte(cfg.cfg), out) diff --git a/service/gzip/service.go b/service/gzip/service.go index 231ba4d9..2ba95158 100644 --- a/service/gzip/service.go +++ b/service/gzip/service.go @@ -2,13 +2,15 @@ package gzip import ( "errors" + "net/http" + "github.com/NYTimes/gziphandler" rrhttp "github.com/spiral/roadrunner/service/http" - "net/http" ) // ID contains default service name. const ID = "gzip" + var httpNotInitialized = errors.New("http service should be defined properly in config to use gzip") type Service struct { diff --git a/service/gzip/service_test.go b/service/gzip/service_test.go index 778bdacd..d886a339 100644 --- a/service/gzip/service_test.go +++ b/service/gzip/service_test.go @@ -1,13 +1,14 @@ package gzip import ( + "testing" + json "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" rrhttp "github.com/spiral/roadrunner/service/http" "github.com/stretchr/testify/assert" - "testing" ) type testCfg struct { diff --git a/service/headers/config_test.go b/service/headers/config_test.go index 6ea02f67..4b7c56df 100644 --- a/service/headers/config_test.go +++ b/service/headers/config_test.go @@ -1,15 +1,16 @@ package headers import ( + "testing" + json "github.com/json-iterator/go" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" - "testing" ) type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { j := json.ConfigCompatibleWithStandardLibrary return j.Unmarshal([]byte(cfg.cfg), out) diff --git a/service/headers/service.go b/service/headers/service.go index 429219d7..a3a9d9da 100644 --- a/service/headers/service.go +++ b/service/headers/service.go @@ -1,9 +1,10 @@ package headers import ( - rrhttp "github.com/spiral/roadrunner/service/http" "net/http" "strconv" + + rrhttp "github.com/spiral/roadrunner/service/http" ) // ID contains default service name. diff --git a/service/headers/service_test.go b/service/headers/service_test.go index a67def02..03a55d1e 100644 --- a/service/headers/service_test.go +++ b/service/headers/service_test.go @@ -1,6 +1,11 @@ package headers import ( + "io/ioutil" + "net/http" + "testing" + "time" + "github.com/cenkalti/backoff/v4" json "github.com/json-iterator/go" "github.com/sirupsen/logrus" @@ -8,10 +13,6 @@ import ( "github.com/spiral/roadrunner/service" rrhttp "github.com/spiral/roadrunner/service/http" "github.com/stretchr/testify/assert" - "io/ioutil" - "net/http" - "testing" - "time" ) type testCfg struct { diff --git a/service/health/config_test.go b/service/health/config_test.go index ba7d7c12..c02c46fc 100644 --- a/service/health/config_test.go +++ b/service/health/config_test.go @@ -1,16 +1,17 @@ package health import ( - json "github.com/json-iterator/go" "testing" + json "github.com/json-iterator/go" + "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" ) type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { j := json.ConfigCompatibleWithStandardLibrary return j.Unmarshal([]byte(cfg.cfg), out) diff --git a/service/health/service.go b/service/health/service.go index ce127340..b9b22a8a 100644 --- a/service/health/service.go +++ b/service/health/service.go @@ -3,11 +3,12 @@ package health import ( "context" "fmt" - "github.com/sirupsen/logrus" "net/http" "sync" "time" + "github.com/sirupsen/logrus" + rrhttp "github.com/spiral/roadrunner/service/http" ) @@ -45,8 +46,8 @@ func (s *Service) Serve() error { // Configure and start the http server s.mu.Lock() s.http = &http.Server{ - Addr: s.cfg.Address, - Handler: s, + Addr: s.cfg.Address, + Handler: s, IdleTimeout: time.Hour * 24, ReadTimeout: time.Minute * 60, MaxHeaderBytes: maxHeaderSize, diff --git a/service/health/service_test.go b/service/health/service_test.go index fc743a62..3488d631 100644 --- a/service/health/service_test.go +++ b/service/health/service_test.go @@ -1,12 +1,13 @@ package health import ( - json "github.com/json-iterator/go" "io/ioutil" "net/http" "testing" "time" + json "github.com/json-iterator/go" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" diff --git a/service/http/attributes/attributes_test.go b/service/http/attributes/attributes_test.go index 2360fd12..d914f6fa 100644 --- a/service/http/attributes/attributes_test.go +++ b/service/http/attributes/attributes_test.go @@ -1,9 +1,10 @@ package attributes import ( - "github.com/stretchr/testify/assert" "net/http" "testing" + + "github.com/stretchr/testify/assert" ) func TestAllAttributes(t *testing.T) { diff --git a/service/http/config.go b/service/http/config.go index 00f61652..34733e44 100644 --- a/service/http/config.go +++ b/service/http/config.go @@ -3,15 +3,21 @@ package http import ( "errors" "fmt" - "github.com/spiral/roadrunner" - "github.com/spiral/roadrunner/service" "net" + "net/http" "os" "strings" + + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" ) // Config configures RoadRunner HTTP server. type Config struct { + // AppErrorCode is error code for the application errors (default 500) + AppErrorCode uint64 + // Error code for the RR pool or worker errors + InternalErrorCode uint64 // Port and port to handle as http server. Address string @@ -60,7 +66,6 @@ type HTTP2Config struct { func (cfg *HTTP2Config) InitDefaults() error { cfg.Enabled = true cfg.MaxConcurrentStreams = 128 - return nil } @@ -109,6 +114,14 @@ func (c *Config) EnableFCGI() bool { // 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 { + if c.AppErrorCode == 0 { + // set default behaviour - 500 error code + c.AppErrorCode = http.StatusInternalServerError + } + if c.InternalErrorCode == 0 { + // set default behaviour - 500 error code + c.InternalErrorCode = http.StatusInternalServerError + } if c.Workers == nil { c.Workers = &roadrunner.ServerConfig{} } diff --git a/service/http/config_test.go b/service/http/config_test.go index d95e0995..18b8f5a3 100644 --- a/service/http/config_test.go +++ b/service/http/config_test.go @@ -1,21 +1,20 @@ package http import ( - json "github.com/json-iterator/go" - "github.com/spiral/roadrunner" - "github.com/spiral/roadrunner/service" - "github.com/stretchr/testify/assert" "os" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" + "github.com/stretchr/testify/assert" ) type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { - j := json.ConfigCompatibleWithStandardLibrary - return j.Unmarshal([]byte(cfg.cfg), out) + return json.Unmarshal([]byte(cfg.cfg), out) } func Test_Config_Hydrate_Error1(t *testing.T) { diff --git a/service/http/fcgi_test.go b/service/http/fcgi_test.go index e68b2e7f..cf67a68b 100644 --- a/service/http/fcgi_test.go +++ b/service/http/fcgi_test.go @@ -1,15 +1,16 @@ package http import ( + "io/ioutil" + "net/http/httptest" + "testing" + "time" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" "github.com/yookoala/gofast" - "io/ioutil" - "net/http/httptest" - "testing" - "time" ) func Test_FCGI_Service_Echo(t *testing.T) { diff --git a/service/http/handler.go b/service/http/handler.go index eca05483..43f894d7 100644 --- a/service/http/handler.go +++ b/service/http/handler.go @@ -61,11 +61,13 @@ func (e *ResponseEvent) Elapsed() time.Duration { // Handler serves http connections to underlying PHP application using PSR-7 protocol. Context will include request headers, // parsed files and query, payload will include parsed form dataTree (if any). type Handler struct { - cfg *Config - log *logrus.Logger - rr *roadrunner.Server - mul sync.Mutex - lsn func(event int, ctx interface{}) + cfg *Config + log *logrus.Logger + rr *roadrunner.Server + mul sync.Mutex + lsn func(event int, ctx interface{}) + internalErrorCode uint64 + appErrorCode uint64 } // Listen attaches handler event controller. @@ -131,6 +133,10 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // handleError sends error. +/* +handleError distinct RR errors and App errors +You can set return distinct error codes for the App and for the RR +*/ func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error, start time.Time) { // if pipe is broken, there is no sense to write the header // in this case we just report about error @@ -138,8 +144,20 @@ func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error, h.throw(EventError, &ErrorEvent{Request: r, Error: err, start: start, elapsed: time.Since(start)}) return } - // ResponseWriter is ok, write the error code - w.WriteHeader(500) + if errors.Is(err, roadrunner.ErrNoAssociatedPool) || + errors.Is(err, roadrunner.ErrAllocateWorker) || + errors.Is(err, roadrunner.ErrWorkerNotReady) || + errors.Is(err, roadrunner.ErrEmptyPayload) || + errors.Is(err, roadrunner.ErrPoolStopped) || + errors.Is(err, roadrunner.ErrWorkerAllocateTimeout) || + errors.Is(err, roadrunner.ErrAllWorkersAreDead) { + // for the RR errors, write custom error code + w.WriteHeader(int(h.internalErrorCode)) + } else { + // ResponseWriter is ok, write the error code + w.WriteHeader(int(h.appErrorCode)) + } + _, err2 := w.Write([]byte(err.Error())) // error during the writing to the ResponseWriter if err2 != nil { diff --git a/service/http/handler_test.go b/service/http/handler_test.go index 951bcbfd..7a50bf97 100644 --- a/service/http/handler_test.go +++ b/service/http/handler_test.go @@ -3,8 +3,6 @@ package http import ( "bytes" "context" - "github.com/spiral/roadrunner" - "github.com/stretchr/testify/assert" "io/ioutil" "mime/multipart" "net/http" @@ -15,6 +13,9 @@ import ( "strings" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/stretchr/testify/assert" ) // get request and return body @@ -110,6 +111,7 @@ func TestHandler_Echo(t *testing.T) { func Test_HandlerErrors(t *testing.T) { h := &Handler{ + internalErrorCode: 500, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -135,8 +137,38 @@ func Test_HandlerErrors(t *testing.T) { assert.Equal(t, 500, wr.Code) } +func Test_HandlerErrorsPoolErrorCode(t *testing.T) { + h := &Handler{ + internalErrorCode: 777, + cfg: &Config{ + MaxRequestSize: 1024, + Uploads: &UploadsConfig{ + Dir: os.TempDir(), + Forbid: []string{}, + }, + }, + rr: roadrunner.NewServer(&roadrunner.ServerConfig{ + Command: "php ../../tests/http/client.php echo pipes", + Relay: "pipes", + Pool: &roadrunner.Config{ + NumWorkers: 1, + AllocateTimeout: 10000000, + DestroyTimeout: 10000000, + }, + }), + } + + wr := httptest.NewRecorder() + rq := httptest.NewRequest("POST", "/", bytes.NewBuffer([]byte("data"))) + + h.ServeHTTP(wr, rq) + assert.Equal(t, 777, wr.Code) +} + func Test_Handler_JSON_error(t *testing.T) { h := &Handler{ + appErrorCode: 500, + internalErrorCode: 500, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1329,6 +1361,8 @@ func TestHandler_Multipart_PATCH(t *testing.T) { func TestHandler_Error(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1373,6 +1407,8 @@ func TestHandler_Error(t *testing.T) { func TestHandler_Error2(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1417,6 +1453,8 @@ func TestHandler_Error2(t *testing.T) { func TestHandler_Error3(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1, Uploads: &UploadsConfig{ @@ -1478,6 +1516,8 @@ func TestHandler_Error3(t *testing.T) { func TestHandler_ResponseDuration(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, + internalErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1596,6 +1636,7 @@ func TestHandler_ResponseDurationDelayed(t *testing.T) { func TestHandler_ErrorDuration(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ @@ -1654,6 +1695,7 @@ func TestHandler_ErrorDuration(t *testing.T) { func TestHandler_IP(t *testing.T) { h := &Handler{ + appErrorCode: http.StatusInternalServerError, cfg: &Config{ MaxRequestSize: 1024, Uploads: &UploadsConfig{ diff --git a/service/http/request.go b/service/http/request.go index 8da5440f..f3fff198 100644 --- a/service/http/request.go +++ b/service/http/request.go @@ -8,7 +8,6 @@ import ( "net/url" "strings" - json "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/spiral/roadrunner" "github.com/spiral/roadrunner/service/http/attributes" @@ -136,13 +135,12 @@ func (r *Request) Close(log *logrus.Logger) { func (r *Request) Payload() (p *roadrunner.Payload, err error) { p = &roadrunner.Payload{} - j := json.ConfigCompatibleWithStandardLibrary - if p.Context, err = j.Marshal(r); err != nil { + if p.Context, err = json.Marshal(r); err != nil { return nil, err } if r.Parsed { - if p.Body, err = j.Marshal(r.body); err != nil { + if p.Body, err = json.Marshal(r.body); err != nil { return nil, err } } else if r.body != nil { diff --git a/service/http/response.go b/service/http/response.go index f34754be..a2540edf 100644 --- a/service/http/response.go +++ b/service/http/response.go @@ -5,11 +5,12 @@ import ( "net/http" "strings" - json "github.com/json-iterator/go" + j "github.com/json-iterator/go" "github.com/spiral/roadrunner" ) +var json = j.ConfigCompatibleWithStandardLibrary // Response handles PSR7 response logic. type Response struct { @@ -26,8 +27,8 @@ type Response struct { // NewResponse creates new response based on given rr payload. func NewResponse(p *roadrunner.Payload) (*Response, error) { r := &Response{body: p.Body} - j := json.ConfigCompatibleWithStandardLibrary - if err := j.Unmarshal(p.Context, r); err != nil { + + if err := json.Unmarshal(p.Context, r); err != nil { return nil, err } diff --git a/service/http/rpc_test.go b/service/http/rpc_test.go index e57a8699..62f27ede 100644 --- a/service/http/rpc_test.go +++ b/service/http/rpc_test.go @@ -1,16 +1,16 @@ package http import ( - json "github.com/json-iterator/go" + "os" + "strconv" + "testing" + "time" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/rpc" "github.com/stretchr/testify/assert" - "os" - "strconv" - "testing" - "time" ) func Test_RPC(t *testing.T) { @@ -88,8 +88,7 @@ func Test_RPC_Unix(t *testing.T) { c.Register(ID, &Service{}) sock := `unix://` + os.TempDir() + `/rpc.unix` - j := json.ConfigCompatibleWithStandardLibrary - data, _ := j.Marshal(sock) + data, _ := json.Marshal(sock) assert.NoError(t, c.Init(&testCfg{ rpcCfg: `{"enable":true, "listen":` + string(data) + `}`, diff --git a/service/http/service.go b/service/http/service.go index 25a10064..7a175dcb 100644 --- a/service/http/service.go +++ b/service/http/service.go @@ -118,7 +118,12 @@ func (s *Service) Serve() error { s.rr.Attach(s.controller) } - s.handler = &Handler{cfg: s.cfg, rr: s.rr} + s.handler = &Handler{ + cfg: s.cfg, + rr: s.rr, + internalErrorCode: s.cfg.InternalErrorCode, + appErrorCode: s.cfg.AppErrorCode, + } s.handler.Listen(s.throw) if s.cfg.EnableHTTP() { diff --git a/service/http/service_test.go b/service/http/service_test.go index f7ee33cc..960bc513 100644 --- a/service/http/service_test.go +++ b/service/http/service_test.go @@ -1,8 +1,13 @@ package http import ( + "io/ioutil" + "net/http" + "os" + "testing" + "time" + "github.com/cenkalti/backoff/v4" - json "github.com/json-iterator/go" "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner" @@ -10,11 +15,6 @@ import ( "github.com/spiral/roadrunner/service/env" "github.com/spiral/roadrunner/service/rpc" "github.com/stretchr/testify/assert" - "io/ioutil" - "net/http" - "os" - "testing" - "time" ) type testCfg struct { @@ -44,8 +44,7 @@ func (cfg *testCfg) Get(name string) service.Config { return nil } func (cfg *testCfg) Unmarshal(out interface{}) error { - j := json.ConfigCompatibleWithStandardLibrary - return j.Unmarshal([]byte(cfg.target), out) + return json.Unmarshal([]byte(cfg.target), out) } func Test_Service_NoConfig(t *testing.T) { @@ -752,8 +751,7 @@ func Test_Service_Error4(t *testing.T) { func tmpDir() string { p := os.TempDir() - j := json.ConfigCompatibleWithStandardLibrary - r, _ := j.Marshal(p) + r, _ := json.Marshal(p) return string(r) } diff --git a/service/http/ssl_test.go b/service/http/ssl_test.go index cf147be9..8078a3a7 100644 --- a/service/http/ssl_test.go +++ b/service/http/ssl_test.go @@ -2,14 +2,15 @@ package http import ( "crypto/tls" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/spiral/roadrunner/service" - "github.com/stretchr/testify/assert" "io/ioutil" "net/http" "testing" "time" + + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/spiral/roadrunner/service" + "github.com/stretchr/testify/assert" ) var sslClient = &http.Client{ @@ -245,7 +246,6 @@ func Test_SSL_Service_Push(t *testing.T) { assert.Equal(t, 201, r.StatusCode) assert.Equal(t, "WORLD", string(b)) - err2 := r.Body.Close() if err2 != nil { t.Errorf("fail to close the Body: error %v", err2) diff --git a/service/http/uploads.go b/service/http/uploads.go index 39a9eaf2..e369fab2 100644 --- a/service/http/uploads.go +++ b/service/http/uploads.go @@ -2,13 +2,13 @@ package http import ( "fmt" - json "github.com/json-iterator/go" - "github.com/sirupsen/logrus" "io" "io/ioutil" "mime/multipart" "os" "sync" + + "github.com/sirupsen/logrus" ) const ( @@ -42,8 +42,7 @@ type Uploads struct { // MarshalJSON marshal tree tree into JSON. func (u *Uploads) MarshalJSON() ([]byte, error) { - j := json.ConfigCompatibleWithStandardLibrary - return j.Marshal(u.tree) + return json.Marshal(u.tree) } // Open moves all uploaded files to temp directory, return error in case of issue with temp directory. File errors diff --git a/service/http/uploads_config_test.go b/service/http/uploads_config_test.go index 2b6ceebc..ac8bfa1d 100644 --- a/service/http/uploads_config_test.go +++ b/service/http/uploads_config_test.go @@ -1,9 +1,10 @@ package http import ( - "github.com/stretchr/testify/assert" "os" "testing" + + "github.com/stretchr/testify/assert" ) func TestFsConfig_Forbids(t *testing.T) { diff --git a/service/http/uploads_test.go b/service/http/uploads_test.go index 08177c72..bab20d49 100644 --- a/service/http/uploads_test.go +++ b/service/http/uploads_test.go @@ -6,9 +6,6 @@ import ( "crypto/md5" "encoding/hex" "fmt" - json "github.com/json-iterator/go" - "github.com/spiral/roadrunner" - "github.com/stretchr/testify/assert" "io" "io/ioutil" "mime/multipart" @@ -16,6 +13,9 @@ import ( "os" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/stretchr/testify/assert" ) func TestHandler_Upload_File(t *testing.T) { @@ -424,8 +424,7 @@ func fileString(f string, errNo int, mime string) string { v.Size = 0 } - j := json.ConfigCompatibleWithStandardLibrary - r, err := j.Marshal(v) + r, err := json.Marshal(v) if err != nil { fmt.Println(fmt.Errorf("error marshalling fInfo, error: %v", err)) } diff --git a/service/limit/config.go b/service/limit/config.go index 203db11b..7a56280d 100644 --- a/service/limit/config.go +++ b/service/limit/config.go @@ -1,9 +1,10 @@ package limit import ( + "time" + "github.com/spiral/roadrunner" "github.com/spiral/roadrunner/service" - "time" ) // Config of Limit service. diff --git a/service/limit/config_test.go b/service/limit/config_test.go index c79836b8..1f121bc5 100644 --- a/service/limit/config_test.go +++ b/service/limit/config_test.go @@ -1,11 +1,12 @@ package limit import ( + "testing" + "time" + json "github.com/json-iterator/go" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" - "testing" - "time" ) type mockCfg struct{ cfg string } diff --git a/service/limit/controller.go b/service/limit/controller.go index 24a158f7..b4a1c25f 100644 --- a/service/limit/controller.go +++ b/service/limit/controller.go @@ -2,9 +2,10 @@ package limit import ( "fmt" + "time" + "github.com/spiral/roadrunner" "github.com/spiral/roadrunner/util" - "time" ) const ( diff --git a/service/limit/state_filter.go b/service/limit/state_filter.go index cd2eca94..4e05769a 100644 --- a/service/limit/state_filter.go +++ b/service/limit/state_filter.go @@ -1,8 +1,9 @@ package limit import ( - "github.com/spiral/roadrunner" "time" + + "github.com/spiral/roadrunner" ) type stateFilter struct { diff --git a/service/metrics/config_test.go b/service/metrics/config_test.go index 94f97da5..5153ead1 100644 --- a/service/metrics/config_test.go +++ b/service/metrics/config_test.go @@ -11,7 +11,7 @@ import ( type mockCfg struct{ cfg string } -func (cfg *mockCfg) Get(name string) service.Config { return nil } +func (cfg *mockCfg) Get(name string) service.Config { return nil } func (cfg *mockCfg) Unmarshal(out interface{}) error { j := json.ConfigCompatibleWithStandardLibrary return j.Unmarshal([]byte(cfg.cfg), out) diff --git a/service/metrics/rpc_test.go b/service/metrics/rpc_test.go index 2fc4bc32..37af3eec 100644 --- a/service/metrics/rpc_test.go +++ b/service/metrics/rpc_test.go @@ -1,15 +1,16 @@ package metrics import ( + rpc2 "net/rpc" + "strconv" + "testing" + "time" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/rpc" "github.com/stretchr/testify/assert" - rpc2 "net/rpc" - "strconv" - "testing" - "time" ) var port = 5004 diff --git a/service/metrics/service_test.go b/service/metrics/service_test.go index cdb81147..7e11cf85 100644 --- a/service/metrics/service_test.go +++ b/service/metrics/service_test.go @@ -1,6 +1,11 @@ package metrics import ( + "io/ioutil" + "net/http" + "testing" + "time" + json "github.com/json-iterator/go" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -8,10 +13,6 @@ import ( "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/rpc" "github.com/stretchr/testify/assert" - "io/ioutil" - "net/http" - "testing" - "time" ) type testCfg struct { diff --git a/service/reload/config.go b/service/reload/config.go index efc71972..46267045 100644 --- a/service/reload/config.go +++ b/service/reload/config.go @@ -2,9 +2,10 @@ package reload import ( "errors" + "time" + "github.com/spiral/roadrunner" "github.com/spiral/roadrunner/service" - "time" ) // Config is a Reload configuration point. diff --git a/service/reload/config_test.go b/service/reload/config_test.go index 600975d3..b0620aa1 100644 --- a/service/reload/config_test.go +++ b/service/reload/config_test.go @@ -1,9 +1,10 @@ package reload import ( - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/stretchr/testify/assert" ) func Test_Config_Valid(t *testing.T) { diff --git a/service/rpc/config.go b/service/rpc/config.go index a4cf0f91..cc492622 100644 --- a/service/rpc/config.go +++ b/service/rpc/config.go @@ -2,10 +2,11 @@ package rpc import ( "errors" - "github.com/spiral/roadrunner/service" - "github.com/spiral/roadrunner/util" "net" "strings" + + "github.com/spiral/roadrunner/service" + "github.com/spiral/roadrunner/util" ) // Config defines RPC service config. diff --git a/service/rpc/config_test.go b/service/rpc/config_test.go index 1ecd71b3..70d58e84 100644 --- a/service/rpc/config_test.go +++ b/service/rpc/config_test.go @@ -1,10 +1,11 @@ package rpc import ( + "testing" + json "github.com/json-iterator/go" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" - "testing" ) type testCfg struct{ cfg string } diff --git a/service/rpc/service.go b/service/rpc/service.go index 7a649f1b..1d6d7595 100644 --- a/service/rpc/service.go +++ b/service/rpc/service.go @@ -2,11 +2,12 @@ package rpc import ( "errors" + "net/rpc" + "sync" + "github.com/spiral/goridge/v2" "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/env" - "net/rpc" - "sync" ) // ID contains default service name. diff --git a/service/rpc/service_test.go b/service/rpc/service_test.go index 51c1b337..385e818e 100644 --- a/service/rpc/service_test.go +++ b/service/rpc/service_test.go @@ -1,11 +1,12 @@ package rpc import ( + "testing" + "time" + "github.com/spiral/roadrunner/service" "github.com/spiral/roadrunner/service/env" "github.com/stretchr/testify/assert" - "testing" - "time" ) type testService struct{} diff --git a/service/static/config.go b/service/static/config.go index 3ca20a83..db50c7dd 100644 --- a/service/static/config.go +++ b/service/static/config.go @@ -2,10 +2,11 @@ package static import ( "fmt" - "github.com/spiral/roadrunner/service" "os" "path" "strings" + + "github.com/spiral/roadrunner/service" ) // Config describes file location and controls access to them. diff --git a/service/static/config_test.go b/service/static/config_test.go index 8bf0d372..2bc936bb 100644 --- a/service/static/config_test.go +++ b/service/static/config_test.go @@ -1,10 +1,11 @@ package static import ( + "testing" + json "github.com/json-iterator/go" "github.com/spiral/roadrunner/service" "github.com/stretchr/testify/assert" - "testing" ) type mockCfg struct{ cfg string } diff --git a/service/static/service.go b/service/static/service.go index 95b99860..49dbedab 100644 --- a/service/static/service.go +++ b/service/static/service.go @@ -1,9 +1,10 @@ package static import ( - rrhttp "github.com/spiral/roadrunner/service/http" "net/http" "path" + + rrhttp "github.com/spiral/roadrunner/service/http" ) // ID contains default service name. diff --git a/service/static/service_test.go b/service/static/service_test.go index 842662c9..bbab86c2 100644 --- a/service/static/service_test.go +++ b/service/static/service_test.go @@ -2,18 +2,19 @@ package static import ( "bytes" - json "github.com/json-iterator/go" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/spiral/roadrunner/service" - rrhttp "github.com/spiral/roadrunner/service/http" - "github.com/stretchr/testify/assert" "io" "io/ioutil" "net/http" "os" "testing" "time" + + json "github.com/json-iterator/go" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/spiral/roadrunner/service" + rrhttp "github.com/spiral/roadrunner/service/http" + "github.com/stretchr/testify/assert" ) type testCfg struct { @@ -75,7 +76,6 @@ func Test_Files(t *testing.T) { time.Sleep(time.Second) - b, _, _ := get("http://localhost:8029/sample.txt") assert.Equal(t, "sample", b) c.Stop() @@ -475,7 +475,6 @@ func TestStatic_Headers(t *testing.T) { t.Fatal("can't find output header in response") } - b, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) diff --git a/socket_factory.go b/socket_factory.go index 42196588..f652e056 100644 --- a/socket_factory.go +++ b/socket_factory.go @@ -2,12 +2,13 @@ package roadrunner import ( "fmt" - "github.com/pkg/errors" - "github.com/spiral/goridge/v2" "net" "os/exec" "sync" "time" + + "github.com/pkg/errors" + "github.com/spiral/goridge/v2" ) // SocketFactory connects to external workers using socket server. diff --git a/socket_factory_test.go b/socket_factory_test.go index abb40f16..330b60a5 100644 --- a/socket_factory_test.go +++ b/socket_factory_test.go @@ -1,11 +1,12 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "net" "os/exec" "testing" "time" + + "github.com/stretchr/testify/assert" ) func Test_Tcp_Start(t *testing.T) { diff --git a/state_test.go b/state_test.go index c13c5a88..10547a4b 100644 --- a/state_test.go +++ b/state_test.go @@ -1,8 +1,9 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func Test_NewState(t *testing.T) { diff --git a/static_pool.go b/static_pool.go index c4b6f42d..efd9125a 100644 --- a/static_pool.go +++ b/static_pool.go @@ -1,7 +1,6 @@ package roadrunner import ( - "fmt" "os/exec" "sync" "sync/atomic" @@ -128,6 +127,8 @@ func (p *StaticPool) Remove(w *Worker, err error) bool { return true } +var ErrAllocateWorker = errors.New("unable to allocate worker") + // Exec one task with given payload and context, returns result or error. func (p *StaticPool) Exec(rqs *Payload) (rsp *Payload, err error) { p.tmu.Lock() @@ -138,11 +139,10 @@ func (p *StaticPool) Exec(rqs *Payload) (rsp *Payload, err error) { w, err := p.allocateWorker() if err != nil { - return nil, errors.Wrap(err, "unable to allocate worker") + return nil, ErrAllocateWorker } rsp, err = w.Exec(rqs) - if err != nil { // soft job errors are allowed if _, jobError := err.(JobError); jobError { @@ -186,6 +186,10 @@ func (p *StaticPool) Destroy() { wg.Wait() } +var ErrPoolStopped = errors.New("pool has been stopped") +var ErrWorkerAllocateTimeout = errors.New("worker allocate timeout") +var ErrAllWorkersAreDead = errors.New("all workers are dead") + // finds free worker in a given time interval. Skips dead workers. func (p *StaticPool) allocateWorker() (w *Worker, err error) { // TODO loop counts upward, but its variable is bounded downward. @@ -210,7 +214,7 @@ func (p *StaticPool) allocateWorker() (w *Worker, err error) { return w, nil case <-p.destroy: - return nil, fmt.Errorf("pool has been stopped") + return nil, ErrPoolStopped default: // enable timeout handler } @@ -218,7 +222,7 @@ func (p *StaticPool) allocateWorker() (w *Worker, err error) { timeout := time.NewTimer(p.cfg.AllocateTimeout) select { case <-timeout.C: - return nil, fmt.Errorf("worker timeout (%s)", p.cfg.AllocateTimeout) + return nil, ErrWorkerAllocateTimeout case w = <-p.free: timeout.Stop() @@ -239,11 +243,11 @@ func (p *StaticPool) allocateWorker() (w *Worker, err error) { case <-p.destroy: timeout.Stop() - return nil, fmt.Errorf("pool has been stopped") + return nil, ErrPoolStopped } } - return nil, fmt.Errorf("all workers are dead (%v)", p.cfg.NumWorkers) + return nil, ErrAllWorkersAreDead } // release releases or replaces the worker. diff --git a/static_pool_test.go b/static_pool_test.go index 59822186..e2181292 100644 --- a/static_pool_test.go +++ b/static_pool_test.go @@ -1,7 +1,6 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "log" "os/exec" "runtime" @@ -10,6 +9,8 @@ import ( "sync" "testing" "time" + + "github.com/stretchr/testify/assert" ) var cfg = Config{ @@ -172,7 +173,6 @@ func Test_StaticPool_Broken_Replace(t *testing.T) { p.Destroy() } - func Test_StaticPool_Broken_FromOutside(t *testing.T) { p, err := NewPool( func() *exec.Cmd { return exec.Command("php", "tests/client.php", "echo", "pipes") }, @@ -238,7 +238,6 @@ func Test_StaticPool_AllocateTimeout(t *testing.T) { } }() - // to ensure that worker is already busy time.Sleep(time.Millisecond * 10) @@ -246,7 +245,7 @@ func Test_StaticPool_AllocateTimeout(t *testing.T) { if err == nil { t.Fatal("Test_StaticPool_AllocateTimeout exec should raise error") } - assert.Contains(t, err.Error(), "worker timeout") + assert.Contains(t, err.Error(), "unable to allocate worker") <-done p.Destroy() diff --git a/util/network.go b/util/network.go index d858cb0a..f35d842b 100644 --- a/util/network.go +++ b/util/network.go @@ -5,11 +5,12 @@ package util import ( "errors" "fmt" - "github.com/valyala/tcplisten" "net" "os" "strings" "syscall" + + "github.com/valyala/tcplisten" ) // CreateListener crates socket listener based on DSN definition. diff --git a/util/network_test.go b/util/network_test.go index 09157ec0..1dc16e94 100644 --- a/util/network_test.go +++ b/util/network_test.go @@ -3,8 +3,9 @@ package util import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestCreateListener(t *testing.T) { diff --git a/util/network_windows_test.go b/util/network_windows_test.go index a5a8064e..3fdc8a5c 100644 --- a/util/network_windows_test.go +++ b/util/network_windows_test.go @@ -3,8 +3,9 @@ package util import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestCreateListener(t *testing.T) { @@ -13,4 +14,4 @@ func TestCreateListener(t *testing.T) { _, err = CreateListener("aaa://192.168.0.1") assert.Error(t, err, "Invalid Protocol (tcp://:6001, unix://file.sock)") -}
\ No newline at end of file +} diff --git a/util/state.go b/util/state.go index 29fca945..5a08f9f2 100644 --- a/util/state.go +++ b/util/state.go @@ -2,6 +2,7 @@ package util import ( "errors" + "github.com/shirou/gopsutil/process" "github.com/spiral/roadrunner" ) diff --git a/util/state_test.go b/util/state_test.go index 2afe682e..2a4a140b 100644 --- a/util/state_test.go +++ b/util/state_test.go @@ -1,11 +1,12 @@ package util import ( - "github.com/spiral/roadrunner" - "github.com/stretchr/testify/assert" "runtime" "testing" "time" + + "github.com/spiral/roadrunner" + "github.com/stretchr/testify/assert" ) func TestServerState(t *testing.T) { @@ -153,6 +153,9 @@ func (w *Worker) Kill() error { } } +var ErrEmptyPayload = errors.New("payload can not be empty") +var ErrWorkerNotReady = errors.New("worker is not ready") + // Exec sends payload to worker, executes it and returns result or // error. Make sure to handle worker.Wait() to gather worker level // errors. Method might return JobError indicating issue with payload. @@ -161,12 +164,12 @@ func (w *Worker) Exec(rqs *Payload) (rsp *Payload, err error) { if rqs == nil { w.mu.Unlock() - return nil, fmt.Errorf("payload can not be empty") + return nil, ErrEmptyPayload } if w.state.Value() != StateReady { w.mu.Unlock() - return nil, fmt.Errorf("worker is not ready (%s)", w.state.String()) + return nil, ErrWorkerNotReady } w.state.set(StateWorking) diff --git a/worker_test.go b/worker_test.go index c21e67cb..8f93ee96 100644 --- a/worker_test.go +++ b/worker_test.go @@ -1,10 +1,11 @@ package roadrunner import ( - "github.com/stretchr/testify/assert" "os/exec" "testing" "time" + + "github.com/stretchr/testify/assert" ) func Test_GetState(t *testing.T) { @@ -112,7 +113,7 @@ func Test_NotStarted_Exec(t *testing.T) { assert.Error(t, err) assert.Nil(t, res) - assert.Equal(t, "worker is not ready (inactive)", err.Error()) + assert.Equal(t, "worker is not ready", err.Error()) } func Test_String(t *testing.T) { |