transport: flatten RetryConfig to value type, replace nil sentinel with Disabled bool
This commit is contained in:
+16
-5
@@ -36,7 +36,9 @@ func TestApplyPoolOptions(t *testing.T) {
|
|||||||
conf := &PoolConfig{}
|
conf := &PoolConfig{}
|
||||||
err := applyPoolOptions(
|
err := applyPoolOptions(
|
||||||
conf,
|
conf,
|
||||||
WithConnectionConfig(&transport.ConnectionConfig{}),
|
WithConnectionConfig(&transport.ConnectionConfig{
|
||||||
|
Retry: transport.RetryConfig{Disabled: true},
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -57,7 +59,10 @@ func TestWithBufferSizes(t *testing.T) {
|
|||||||
|
|
||||||
func TestWithConnectionConfig(t *testing.T) {
|
func TestWithConnectionConfig(t *testing.T) {
|
||||||
conf := &PoolConfig{}
|
conf := &PoolConfig{}
|
||||||
opt := WithConnectionConfig(&transport.ConnectionConfig{WriteTimeout: 1 * time.Second})
|
opt := WithConnectionConfig(&transport.ConnectionConfig{
|
||||||
|
WriteTimeout: 1 * time.Second,
|
||||||
|
Retry: transport.RetryConfig{Disabled: true},
|
||||||
|
})
|
||||||
err := applyPoolOptions(conf, opt)
|
err := applyPoolOptions(conf, opt)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, conf.ConnectionConfig)
|
assert.NotNil(t, conf.ConnectionConfig)
|
||||||
@@ -65,7 +70,11 @@ func TestWithConnectionConfig(t *testing.T) {
|
|||||||
|
|
||||||
// invalid config is rejected
|
// invalid config is rejected
|
||||||
conf = &PoolConfig{}
|
conf = &PoolConfig{}
|
||||||
opt = WithConnectionConfig(&transport.ConnectionConfig{WriteTimeout: -1 * time.Second})
|
opt = WithConnectionConfig(
|
||||||
|
&transport.ConnectionConfig{
|
||||||
|
WriteTimeout: -1 * time.Second,
|
||||||
|
Retry: transport.RetryConfig{Disabled: true},
|
||||||
|
})
|
||||||
err = applyPoolOptions(conf, opt)
|
err = applyPoolOptions(conf, opt)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
@@ -88,14 +97,16 @@ func TestValidatePoolConfig(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "valid complete",
|
name: "valid complete",
|
||||||
conf: PoolConfig{
|
conf: PoolConfig{
|
||||||
ConnectionConfig: &transport.ConnectionConfig{},
|
ConnectionConfig: &transport.ConnectionConfig{
|
||||||
|
Retry: transport.RetryConfig{Disabled: true},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid connection config",
|
name: "invalid connection config",
|
||||||
conf: PoolConfig{
|
conf: PoolConfig{
|
||||||
ConnectionConfig: &transport.ConnectionConfig{
|
ConnectionConfig: &transport.ConnectionConfig{
|
||||||
Retry: &transport.RetryConfig{
|
Retry: transport.RetryConfig{
|
||||||
InitialDelay: 10 * time.Second,
|
InitialDelay: 10 * time.Second,
|
||||||
MaxDelay: 1 * time.Second,
|
MaxDelay: 1 * time.Second,
|
||||||
},
|
},
|
||||||
|
|||||||
+11
-30
@@ -20,10 +20,11 @@ type ConnectionConfig struct {
|
|||||||
PingInterval time.Duration
|
PingInterval time.Duration
|
||||||
IncomingBufferSize int
|
IncomingBufferSize int
|
||||||
ErrorsBufferSize int
|
ErrorsBufferSize int
|
||||||
Retry *RetryConfig
|
Retry RetryConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type RetryConfig struct {
|
type RetryConfig struct {
|
||||||
|
Disabled bool
|
||||||
MaxRetries int
|
MaxRetries int
|
||||||
InitialDelay time.Duration
|
InitialDelay time.Duration
|
||||||
MaxDelay time.Duration
|
MaxDelay time.Duration
|
||||||
@@ -55,16 +56,12 @@ func GetDefaultConnectionConfig() *ConnectionConfig {
|
|||||||
PingInterval: 20 * time.Second,
|
PingInterval: 20 * time.Second,
|
||||||
IncomingBufferSize: 100,
|
IncomingBufferSize: 100,
|
||||||
ErrorsBufferSize: 10,
|
ErrorsBufferSize: 10,
|
||||||
Retry: GetDefaultRetryConfig(),
|
Retry: RetryConfig{
|
||||||
}
|
MaxRetries: 0, // Infinite retries
|
||||||
}
|
InitialDelay: 1 * time.Second,
|
||||||
|
MaxDelay: 60 * time.Second,
|
||||||
func GetDefaultRetryConfig() *RetryConfig {
|
JitterFactor: 0.2,
|
||||||
return &RetryConfig{
|
},
|
||||||
MaxRetries: 0, // Infinite retries
|
|
||||||
InitialDelay: 1 * time.Second,
|
|
||||||
MaxDelay: 60 * time.Second,
|
|
||||||
JitterFactor: 0.2,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +82,7 @@ func ValidateConnectionConfig(config *ConnectionConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Retry != nil {
|
if !config.Retry.Disabled {
|
||||||
err = validateMaxRetries(config.Retry.MaxRetries)
|
err = validateMaxRetries(config.Retry.MaxRetries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -223,19 +220,15 @@ func WithErrorsBufferSize(value int) ConnectionOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithoutRetry() ConnectionOption {
|
func WithRetryDisabled() ConnectionOption {
|
||||||
return func(c *ConnectionConfig) error {
|
return func(c *ConnectionConfig) error {
|
||||||
c.Retry = nil
|
c.Retry.Disabled = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithRetryMaxRetries(value int) ConnectionOption {
|
func WithRetryMaxRetries(value int) ConnectionOption {
|
||||||
return func(c *ConnectionConfig) error {
|
return func(c *ConnectionConfig) error {
|
||||||
if c.Retry == nil {
|
|
||||||
c.Retry = GetDefaultRetryConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := validateMaxRetries(value)
|
err := validateMaxRetries(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -248,10 +241,6 @@ func WithRetryMaxRetries(value int) ConnectionOption {
|
|||||||
|
|
||||||
func WithRetryInitialDelay(value time.Duration) ConnectionOption {
|
func WithRetryInitialDelay(value time.Duration) ConnectionOption {
|
||||||
return func(c *ConnectionConfig) error {
|
return func(c *ConnectionConfig) error {
|
||||||
if c.Retry == nil {
|
|
||||||
c.Retry = GetDefaultRetryConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := validateInitialDelay(value)
|
err := validateInitialDelay(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -264,10 +253,6 @@ func WithRetryInitialDelay(value time.Duration) ConnectionOption {
|
|||||||
|
|
||||||
func WithRetryMaxDelay(value time.Duration) ConnectionOption {
|
func WithRetryMaxDelay(value time.Duration) ConnectionOption {
|
||||||
return func(c *ConnectionConfig) error {
|
return func(c *ConnectionConfig) error {
|
||||||
if c.Retry == nil {
|
|
||||||
c.Retry = GetDefaultRetryConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := validateMaxDelay(value)
|
err := validateMaxDelay(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -280,10 +265,6 @@ func WithRetryMaxDelay(value time.Duration) ConnectionOption {
|
|||||||
|
|
||||||
func WithRetryJitterFactor(value float64) ConnectionOption {
|
func WithRetryJitterFactor(value float64) ConnectionOption {
|
||||||
return func(c *ConnectionConfig) error {
|
return func(c *ConnectionConfig) error {
|
||||||
if c.Retry == nil {
|
|
||||||
c.Retry = GetDefaultRetryConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := validateJitterFactor(value)
|
err := validateJitterFactor(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+11
-17
@@ -35,18 +35,12 @@ func TestDefaultConnectionConfig(t *testing.T) {
|
|||||||
PingInterval: 20 * time.Second,
|
PingInterval: 20 * time.Second,
|
||||||
IncomingBufferSize: 100,
|
IncomingBufferSize: 100,
|
||||||
ErrorsBufferSize: 10,
|
ErrorsBufferSize: 10,
|
||||||
Retry: GetDefaultRetryConfig(),
|
Retry: RetryConfig{
|
||||||
})
|
MaxRetries: 0,
|
||||||
}
|
InitialDelay: 1 * time.Second,
|
||||||
|
MaxDelay: 60 * time.Second,
|
||||||
func TestDefaultRetryConnectionConfig(t *testing.T) {
|
JitterFactor: 0.2,
|
||||||
conf := GetDefaultRetryConfig()
|
},
|
||||||
|
|
||||||
assert.Equal(t, conf, &RetryConfig{
|
|
||||||
MaxRetries: 0,
|
|
||||||
InitialDelay: 1 * time.Second,
|
|
||||||
MaxDelay: 60 * time.Second,
|
|
||||||
JitterFactor: 0.2,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,10 +108,10 @@ func TestWithWriteTimeout(t *testing.T) {
|
|||||||
func TestWithRetry(t *testing.T) {
|
func TestWithRetry(t *testing.T) {
|
||||||
t.Run("without retry", func(t *testing.T) {
|
t.Run("without retry", func(t *testing.T) {
|
||||||
conf := GetDefaultConnectionConfig()
|
conf := GetDefaultConnectionConfig()
|
||||||
opt := WithoutRetry()
|
opt := WithRetryDisabled()
|
||||||
err := applyConnectionOptions(conf, opt)
|
err := applyConnectionOptions(conf, opt)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, conf.Retry)
|
assert.True(t, conf.Retry.Disabled)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with attempts", func(t *testing.T) {
|
t.Run("with attempts", func(t *testing.T) {
|
||||||
@@ -209,7 +203,7 @@ func TestValidateConnectionConfig(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "valid empty",
|
name: "valid empty",
|
||||||
conf: *&ConnectionConfig{},
|
conf: ConnectionConfig{Retry: RetryConfig{Disabled: true}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid defaults",
|
name: "valid defaults",
|
||||||
@@ -220,7 +214,7 @@ func TestValidateConnectionConfig(t *testing.T) {
|
|||||||
conf: ConnectionConfig{
|
conf: ConnectionConfig{
|
||||||
CloseHandler: (func(code int, text string) error { return nil }),
|
CloseHandler: (func(code int, text string) error { return nil }),
|
||||||
WriteTimeout: time.Duration(30),
|
WriteTimeout: time.Duration(30),
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
MaxRetries: 0,
|
MaxRetries: 0,
|
||||||
InitialDelay: 2 * time.Second,
|
InitialDelay: 2 * time.Second,
|
||||||
MaxDelay: 10 * time.Second,
|
MaxDelay: 10 * time.Second,
|
||||||
@@ -231,7 +225,7 @@ func TestValidateConnectionConfig(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid - initial delay > max delay",
|
name: "invalid - initial delay > max delay",
|
||||||
conf: ConnectionConfig{
|
conf: ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
InitialDelay: 10 * time.Second,
|
InitialDelay: 10 * time.Second,
|
||||||
MaxDelay: 1 * time.Second,
|
MaxDelay: 1 * time.Second,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func TestConnectionSend(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("write timeout disabled when zero", func(t *testing.T) {
|
t.Run("write timeout disabled when zero", func(t *testing.T) {
|
||||||
config := &ConnectionConfig{WriteTimeout: 0}
|
config := &ConnectionConfig{WriteTimeout: 0, Retry: RetryConfig{Disabled: true}}
|
||||||
|
|
||||||
outgoingData := make(chan honeybeetest.MockOutgoingData, 10)
|
outgoingData := make(chan honeybeetest.MockOutgoingData, 10)
|
||||||
mockSocket := honeybeetest.NewMockSocket()
|
mockSocket := honeybeetest.NewMockSocket()
|
||||||
@@ -148,7 +148,7 @@ func TestConnectionSend(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("write timeout sets deadline when positive", func(t *testing.T) {
|
t.Run("write timeout sets deadline when positive", func(t *testing.T) {
|
||||||
config := &ConnectionConfig{WriteTimeout: 30 * time.Millisecond}
|
config := &ConnectionConfig{WriteTimeout: 30 * time.Millisecond, Retry: RetryConfig{Disabled: true}}
|
||||||
|
|
||||||
outgoingData := make(chan honeybeetest.MockOutgoingData, 10)
|
outgoingData := make(chan honeybeetest.MockOutgoingData, 10)
|
||||||
mockSocket := honeybeetest.NewMockSocket()
|
mockSocket := honeybeetest.NewMockSocket()
|
||||||
@@ -194,7 +194,7 @@ func TestConnectionSend(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("send fails on deadline error", func(t *testing.T) {
|
t.Run("send fails on deadline error", func(t *testing.T) {
|
||||||
config := &ConnectionConfig{WriteTimeout: 1 * time.Millisecond}
|
config := &ConnectionConfig{WriteTimeout: 1 * time.Millisecond, Retry: RetryConfig{Disabled: true}}
|
||||||
|
|
||||||
mockSocket := honeybeetest.NewMockSocket()
|
mockSocket := honeybeetest.NewMockSocket()
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func TestNewConnection(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "valid url, valid config",
|
name: "valid url, valid config",
|
||||||
url: "wss://relay.example.com:8080/path",
|
url: "wss://relay.example.com:8080/path",
|
||||||
config: &ConnectionConfig{WriteTimeout: 30 * time.Second},
|
config: &ConnectionConfig{WriteTimeout: 30 * time.Second, Retry: RetryConfig{Disabled: true}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid url",
|
name: "invalid url",
|
||||||
@@ -82,7 +82,7 @@ func TestNewConnection(t *testing.T) {
|
|||||||
name: "invalid config",
|
name: "invalid config",
|
||||||
url: "ws://example.com",
|
url: "ws://example.com",
|
||||||
config: &ConnectionConfig{
|
config: &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
InitialDelay: 10 * time.Second,
|
InitialDelay: 10 * time.Second,
|
||||||
MaxDelay: 1 * time.Second,
|
MaxDelay: 1 * time.Second,
|
||||||
},
|
},
|
||||||
@@ -152,13 +152,13 @@ func TestNewConnectionFromSocket(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "valid socket with valid config",
|
name: "valid socket with valid config",
|
||||||
socket: honeybeetest.NewMockSocket(),
|
socket: honeybeetest.NewMockSocket(),
|
||||||
config: &ConnectionConfig{WriteTimeout: 30 * time.Second},
|
config: &ConnectionConfig{WriteTimeout: 30 * time.Second, Retry: RetryConfig{Disabled: true}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid config",
|
name: "invalid config",
|
||||||
socket: honeybeetest.NewMockSocket(),
|
socket: honeybeetest.NewMockSocket(),
|
||||||
config: &ConnectionConfig{
|
config: &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
InitialDelay: 10 * time.Second,
|
InitialDelay: 10 * time.Second,
|
||||||
MaxDelay: 1 * time.Second,
|
MaxDelay: 1 * time.Second,
|
||||||
},
|
},
|
||||||
@@ -173,6 +173,7 @@ func TestNewConnectionFromSocket(t *testing.T) {
|
|||||||
CloseHandler: func(code int, text string) error {
|
CloseHandler: func(code int, text string) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
Retry: RetryConfig{Disabled: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -299,7 +300,7 @@ func TestConnect(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("connect retries on dial failure", func(t *testing.T) {
|
t.Run("connect retries on dial failure", func(t *testing.T) {
|
||||||
config := &ConnectionConfig{
|
config := &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
MaxRetries: 2,
|
MaxRetries: 2,
|
||||||
InitialDelay: 1 * time.Millisecond,
|
InitialDelay: 1 * time.Millisecond,
|
||||||
MaxDelay: 5 * time.Millisecond,
|
MaxDelay: 5 * time.Millisecond,
|
||||||
@@ -331,7 +332,7 @@ func TestConnect(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("connect fails after max retries", func(t *testing.T) {
|
t.Run("connect fails after max retries", func(t *testing.T) {
|
||||||
config := &ConnectionConfig{
|
config := &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
MaxRetries: 2,
|
MaxRetries: 2,
|
||||||
InitialDelay: 1 * time.Millisecond,
|
InitialDelay: 1 * time.Millisecond,
|
||||||
MaxDelay: 5 * time.Millisecond,
|
MaxDelay: 5 * time.Millisecond,
|
||||||
@@ -382,6 +383,7 @@ func TestConnect(t *testing.T) {
|
|||||||
CloseHandler: func(code int, text string) error {
|
CloseHandler: func(code int, text string) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
Retry: RetryConfig{Disabled: true},
|
||||||
}
|
}
|
||||||
conn, err := NewConnection(context.Background(), "ws://test", config, nil)
|
conn, err := NewConnection(context.Background(), "ws://test", config, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -429,7 +431,7 @@ func TestConnect(t *testing.T) {
|
|||||||
func TestConnectContextCancellation(t *testing.T) {
|
func TestConnectContextCancellation(t *testing.T) {
|
||||||
t.Run("context cancelled during connect returns before retries exhaust", func(t *testing.T) {
|
t.Run("context cancelled during connect returns before retries exhaust", func(t *testing.T) {
|
||||||
config := &ConnectionConfig{
|
config := &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
MaxRetries: 100,
|
MaxRetries: 100,
|
||||||
InitialDelay: 500 * time.Millisecond,
|
InitialDelay: 500 * time.Millisecond,
|
||||||
MaxDelay: 1 * time.Second,
|
MaxDelay: 1 * time.Second,
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func TestConnectLogging(t *testing.T) {
|
|||||||
mockHandler := honeybeetest.NewMockSlogHandler()
|
mockHandler := honeybeetest.NewMockSlogHandler()
|
||||||
|
|
||||||
config := &ConnectionConfig{
|
config := &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
MaxRetries: 2,
|
MaxRetries: 2,
|
||||||
InitialDelay: 1 * time.Millisecond,
|
InitialDelay: 1 * time.Millisecond,
|
||||||
MaxDelay: 5 * time.Millisecond,
|
MaxDelay: 5 * time.Millisecond,
|
||||||
@@ -101,7 +101,7 @@ func TestConnectLogging(t *testing.T) {
|
|||||||
mockHandler := honeybeetest.NewMockSlogHandler()
|
mockHandler := honeybeetest.NewMockSlogHandler()
|
||||||
|
|
||||||
config := &ConnectionConfig{
|
config := &ConnectionConfig{
|
||||||
Retry: &RetryConfig{
|
Retry: RetryConfig{
|
||||||
MaxRetries: 3,
|
MaxRetries: 3,
|
||||||
InitialDelay: 1 * time.Millisecond,
|
InitialDelay: 1 * time.Millisecond,
|
||||||
MaxDelay: 5 * time.Millisecond,
|
MaxDelay: 5 * time.Millisecond,
|
||||||
@@ -279,7 +279,7 @@ func TestWriterLogging(t *testing.T) {
|
|||||||
t.Run("write deadline error", func(t *testing.T) {
|
t.Run("write deadline error", func(t *testing.T) {
|
||||||
mockHandler := honeybeetest.NewMockSlogHandler()
|
mockHandler := honeybeetest.NewMockSlogHandler()
|
||||||
|
|
||||||
config := &ConnectionConfig{WriteTimeout: 1 * time.Millisecond}
|
config := &ConnectionConfig{WriteTimeout: 1 * time.Millisecond, Retry: RetryConfig{Disabled: true}}
|
||||||
|
|
||||||
deadlineErr := fmt.Errorf("deadline error")
|
deadlineErr := fmt.Errorf("deadline error")
|
||||||
mockSocket := honeybeetest.NewMockSocket()
|
mockSocket := honeybeetest.NewMockSocket()
|
||||||
|
|||||||
+6
-6
@@ -7,16 +7,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type RetryManager struct {
|
type RetryManager struct {
|
||||||
config *RetryConfig
|
config RetryConfig
|
||||||
retryCount int
|
retryCount int
|
||||||
saturation int
|
saturation int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRetryManager(config *RetryConfig) *RetryManager {
|
func NewRetryManager(config RetryConfig) *RetryManager {
|
||||||
// saturationCount: retry count at which base delay meets or exceeds MaxDelay.
|
// saturationCount: retry count at which base delay meets or exceeds MaxDelay.
|
||||||
// Conservative by two to preserve jitter variance near the boundary.
|
// Conservative by two to preserve jitter variance near the boundary.
|
||||||
saturation := 0
|
saturation := 0
|
||||||
if config != nil &&
|
if !config.Disabled &&
|
||||||
config.InitialDelay > 0 &&
|
config.InitialDelay > 0 &&
|
||||||
config.InitialDelay <= config.MaxDelay {
|
config.InitialDelay <= config.MaxDelay {
|
||||||
ratio := float64(config.MaxDelay) / float64(config.InitialDelay)
|
ratio := float64(config.MaxDelay) / float64(config.InitialDelay)
|
||||||
@@ -31,7 +31,7 @@ func NewRetryManager(config *RetryConfig) *RetryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RetryManager) ShouldRetry() bool {
|
func (r *RetryManager) ShouldRetry() bool {
|
||||||
if r.config == nil {
|
if r.config.Disabled {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func (r *RetryManager) ShouldRetry() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RetryManager) CalculateDelay() time.Duration {
|
func (r *RetryManager) CalculateDelay() time.Duration {
|
||||||
if r.config == nil {
|
if r.config.Disabled {
|
||||||
return time.Second
|
return time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ func (r *RetryManager) CalculateDelay() time.Duration {
|
|||||||
|
|
||||||
// if saturation is reached, calculated backoff will always be higher than
|
// if saturation is reached, calculated backoff will always be higher than
|
||||||
// the maximum delay
|
// the maximum delay
|
||||||
if r.config != nil && r.retryCount >= r.saturation {
|
if r.retryCount >= r.saturation {
|
||||||
return r.config.MaxDelay
|
return r.config.MaxDelay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewRetryManager(t *testing.T) {
|
func TestNewRetryManager(t *testing.T) {
|
||||||
config := &RetryConfig{
|
config := RetryConfig{
|
||||||
MaxRetries: 0,
|
MaxRetries: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,14 +16,14 @@ func TestNewRetryManager(t *testing.T) {
|
|||||||
assert.Equal(t, config, mgr.config)
|
assert.Equal(t, config, mgr.config)
|
||||||
assert.Equal(t, 0, mgr.retryCount)
|
assert.Equal(t, 0, mgr.retryCount)
|
||||||
|
|
||||||
// Should accept nil config
|
// Should accept a disabled config
|
||||||
mgr = NewRetryManager(nil)
|
mgr = NewRetryManager(RetryConfig{Disabled: true})
|
||||||
assert.Nil(t, mgr.config)
|
assert.True(t, mgr.config.Disabled)
|
||||||
assert.Equal(t, 0, mgr.retryCount)
|
assert.Equal(t, 0, mgr.retryCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecordRetry(t *testing.T) {
|
func TestRecordRetry(t *testing.T) {
|
||||||
mgr := NewRetryManager(nil)
|
mgr := NewRetryManager(RetryConfig{Disabled: true})
|
||||||
assert.Equal(t, mgr.retryCount, 0)
|
assert.Equal(t, mgr.retryCount, 0)
|
||||||
|
|
||||||
mgr.RecordRetry()
|
mgr.RecordRetry()
|
||||||
@@ -34,13 +34,13 @@ func TestRecordRetry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldRetry(t *testing.T) {
|
func TestShouldRetry(t *testing.T) {
|
||||||
// never retry if config is nil
|
// never retry if config is disabled
|
||||||
mgr := NewRetryManager(nil)
|
mgr := NewRetryManager(RetryConfig{Disabled: true})
|
||||||
assert.False(t, mgr.ShouldRetry())
|
assert.False(t, mgr.ShouldRetry())
|
||||||
|
|
||||||
// always retry if max attempt count is zero
|
// always retry if max attempt count is zero
|
||||||
mgr = &RetryManager{
|
mgr = &RetryManager{
|
||||||
config: &RetryConfig{
|
config: RetryConfig{
|
||||||
MaxRetries: 0,
|
MaxRetries: 0,
|
||||||
},
|
},
|
||||||
retryCount: 1000,
|
retryCount: 1000,
|
||||||
@@ -49,7 +49,7 @@ func TestShouldRetry(t *testing.T) {
|
|||||||
|
|
||||||
// retry if below max attempt count
|
// retry if below max attempt count
|
||||||
mgr = &RetryManager{
|
mgr = &RetryManager{
|
||||||
config: &RetryConfig{
|
config: RetryConfig{
|
||||||
MaxRetries: 10,
|
MaxRetries: 10,
|
||||||
},
|
},
|
||||||
retryCount: 5,
|
retryCount: 5,
|
||||||
@@ -58,7 +58,7 @@ func TestShouldRetry(t *testing.T) {
|
|||||||
|
|
||||||
// do not retry if above max attempt count
|
// do not retry if above max attempt count
|
||||||
mgr = &RetryManager{
|
mgr = &RetryManager{
|
||||||
config: &RetryConfig{
|
config: RetryConfig{
|
||||||
MaxRetries: 10,
|
MaxRetries: 10,
|
||||||
},
|
},
|
||||||
retryCount: 11,
|
retryCount: 11,
|
||||||
@@ -68,12 +68,12 @@ func TestShouldRetry(t *testing.T) {
|
|||||||
|
|
||||||
func TestCalculateDelayDisabled(t *testing.T) {
|
func TestCalculateDelayDisabled(t *testing.T) {
|
||||||
// default delay if retry is disabled
|
// default delay if retry is disabled
|
||||||
mgr := NewRetryManager(nil)
|
mgr := NewRetryManager(RetryConfig{Disabled: true})
|
||||||
assert.Equal(t, time.Second, mgr.CalculateDelay())
|
assert.Equal(t, time.Second, mgr.CalculateDelay())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalculateDelayWithoutJitter(t *testing.T) {
|
func TestCalculateDelayWithoutJitter(t *testing.T) {
|
||||||
mgr := NewRetryManager(&RetryConfig{
|
mgr := NewRetryManager(RetryConfig{
|
||||||
MaxRetries: 0,
|
MaxRetries: 0,
|
||||||
InitialDelay: 1 * time.Second,
|
InitialDelay: 1 * time.Second,
|
||||||
MaxDelay: 5 * time.Second,
|
MaxDelay: 5 * time.Second,
|
||||||
@@ -105,7 +105,7 @@ func TestCalculateDelayWithoutJitter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCalculateDelayWithJitter(t *testing.T) {
|
func TestCalculateDelayWithJitter(t *testing.T) {
|
||||||
mgr := NewRetryManager(&RetryConfig{
|
mgr := NewRetryManager(RetryConfig{
|
||||||
MaxRetries: 0,
|
MaxRetries: 0,
|
||||||
InitialDelay: 1 * time.Second,
|
InitialDelay: 1 * time.Second,
|
||||||
MaxDelay: 5 * time.Second,
|
MaxDelay: 5 * time.Second,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func TestAcquireSocket(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
retryMgr := NewRetryManager(&RetryConfig{
|
retryMgr := NewRetryManager(RetryConfig{
|
||||||
MaxRetries: tc.maxRetries,
|
MaxRetries: tc.maxRetries,
|
||||||
InitialDelay: 1 * time.Millisecond,
|
InitialDelay: 1 * time.Millisecond,
|
||||||
MaxDelay: 5 * time.Millisecond,
|
MaxDelay: 5 * time.Millisecond,
|
||||||
@@ -106,7 +106,8 @@ func TestAcquireSocketGuards(t *testing.T) {
|
|||||||
return honeybeetest.NewMockSocket(), nil, nil
|
return honeybeetest.NewMockSocket(), nil, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
validRetryMgr := NewRetryManager(GetDefaultRetryConfig())
|
validRetryConfig := GetDefaultConnectionConfig().Retry
|
||||||
|
validRetryMgr := NewRetryManager(validRetryConfig)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -167,7 +168,7 @@ func TestAcquireSocketContextCancellation(t *testing.T) {
|
|||||||
// cancel before acquiring socket
|
// cancel before acquiring socket
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
retryMgr := NewRetryManager(GetDefaultRetryConfig())
|
retryMgr := NewRetryManager(GetDefaultConnectionConfig().Retry)
|
||||||
_, _, err := AcquireSocket(ctx, retryMgr, mockDialer, "ws://test", nil, nil)
|
_, _, err := AcquireSocket(ctx, retryMgr, mockDialer, "ws://test", nil, nil)
|
||||||
|
|
||||||
assert.ErrorIs(t, err, context.Canceled)
|
assert.ErrorIs(t, err, context.Canceled)
|
||||||
@@ -186,7 +187,7 @@ func TestAcquireSocketContextCancellation(t *testing.T) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
retryMgr := NewRetryManager(&RetryConfig{
|
retryMgr := NewRetryManager(RetryConfig{
|
||||||
MaxRetries: 10,
|
MaxRetries: 10,
|
||||||
InitialDelay: 1 * time.Second,
|
InitialDelay: 1 * time.Second,
|
||||||
MaxDelay: 1 * time.Second,
|
MaxDelay: 1 * time.Second,
|
||||||
@@ -230,7 +231,7 @@ func TestAcquireSocketContextCancellation(t *testing.T) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
retryMgr := NewRetryManager(GetDefaultRetryConfig())
|
retryMgr := NewRetryManager(GetDefaultConnectionConfig().Retry)
|
||||||
done := make(chan error, 1)
|
done := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
_, _, err := AcquireSocket(ctx, retryMgr, mockDialer, "ws://test", nil, nil)
|
_, _, err := AcquireSocket(ctx, retryMgr, mockDialer, "ws://test", nil, nil)
|
||||||
@@ -263,7 +264,7 @@ func TestAcquireSocketPassesHeaders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
retryMgr := NewRetryManager(&RetryConfig{MaxRetries: 0})
|
retryMgr := NewRetryManager(RetryConfig{MaxRetries: 0, InitialDelay: 1 * time.Millisecond, MaxDelay: 5 * time.Millisecond})
|
||||||
_, _, err := AcquireSocket(context.Background(), retryMgr, mockDialer, "ws://test", header, nil)
|
_, _, err := AcquireSocket(context.Background(), retryMgr, mockDialer, "ws://test", header, nil)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|||||||
+3
-3
@@ -94,7 +94,7 @@ func TestWorkerSession(t *testing.T) {
|
|||||||
return nil, nil, errors.New("connection refused")
|
return nil, nil, errors.New("connection refused")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cc, _ := transport.NewConnectionConfig(transport.WithoutRetry())
|
cc, _ := transport.NewConnectionConfig(transport.WithRetryDisabled())
|
||||||
pool.ConnectionConfig = cc
|
pool.ConnectionConfig = cc
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -150,7 +150,7 @@ func TestWorkerSession(t *testing.T) {
|
|||||||
return nil, nil, dialCtx.Err()
|
return nil, nil, dialCtx.Err()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cc, _ := transport.NewConnectionConfig(transport.WithoutRetry())
|
cc, _ := transport.NewConnectionConfig(transport.WithRetryDisabled())
|
||||||
pool.ConnectionConfig = cc
|
pool.ConnectionConfig = cc
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -175,7 +175,7 @@ func TestWorkerSession(t *testing.T) {
|
|||||||
return nil, nil, dialCtx.Err()
|
return nil, nil, dialCtx.Err()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cc, _ := transport.NewConnectionConfig(transport.WithoutRetry())
|
cc, _ := transport.NewConnectionConfig(transport.WithRetryDisabled())
|
||||||
pool.ConnectionConfig = cc
|
pool.ConnectionConfig = cc
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|||||||
Reference in New Issue
Block a user