diff --git a/exponential.go b/exponential.go index 2c56c1e..aac99f1 100644 --- a/exponential.go +++ b/exponential.go @@ -71,6 +71,9 @@ type Clock interface { Now() time.Time } +// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options. +type ExponentialBackOffOpts func(*ExponentialBackOff) + // Default values for ExponentialBackOff. const ( DefaultInitialInterval = 500 * time.Millisecond @@ -81,7 +84,7 @@ const ( ) // NewExponentialBackOff creates an instance of ExponentialBackOff using default values. -func NewExponentialBackOff() *ExponentialBackOff { +func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff { b := &ExponentialBackOff{ InitialInterval: DefaultInitialInterval, RandomizationFactor: DefaultRandomizationFactor, @@ -91,10 +94,62 @@ func NewExponentialBackOff() *ExponentialBackOff { Stop: Stop, Clock: SystemClock, } + for _, fn := range opts { + fn(b) + } b.Reset() return b } +// WithInitialInterval sets the initial interval between retries. +func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.InitialInterval = duration + } +} + +// WithRandomizationFactor sets the randomization factor to add jitter to intervals. +func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.RandomizationFactor = randomizationFactor + } +} + +// WithMultiplier sets the multiplier for increasing the interval after each retry. +func WithMultiplier(multiplier float64) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.Multiplier = multiplier + } +} + +// WithMaxInterval sets the maximum interval between retries. +func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.MaxInterval = duration + } +} + +// WithMaxElapsedTime sets the maximum total time for retries. +func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.MaxElapsedTime = duration + } +} + +// WithRetryStopDuration sets the duration after which retries should stop. +func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.Stop = duration + } +} + +// WithClockProvider sets the clock used to measure time. +func WithClockProvider(clock Clock) ExponentialBackOffOpts { + return func(ebo *ExponentialBackOff) { + ebo.Clock = clock + } +} + type systemClock struct{} func (t systemClock) Now() time.Time { diff --git a/exponential_test.go b/exponential_test.go index 1cc1bf3..7cc75d8 100644 --- a/exponential_test.go +++ b/exponential_test.go @@ -117,3 +117,45 @@ func assertEquals(t *testing.T, expected, value time.Duration) { t.Errorf("got: %d, expected: %d", value, expected) } } + +func TestNewExponentialBackOff(t *testing.T) { + // Create a new ExponentialBackOff with custom options + backOff := NewExponentialBackOff( + WithInitialInterval(1*time.Second), + WithMultiplier(2.0), + WithMaxInterval(10*time.Second), + WithMaxElapsedTime(30*time.Second), + WithRetryStopDuration(0), + WithClockProvider(SystemClock), + ) + + // Check that the backOff object is not nil + if backOff == nil { + t.Error("Expected a non-nil ExponentialBackOff object, got nil") + } + + // Check that the custom options were applied correctly + if backOff.InitialInterval != 1*time.Second { + t.Errorf("Expected InitialInterval to be 1 second, got %v", backOff.InitialInterval) + } + + if backOff.Multiplier != 2.0 { + t.Errorf("Expected Multiplier to be 2.0, got %v", backOff.Multiplier) + } + + if backOff.MaxInterval != 10*time.Second { + t.Errorf("Expected MaxInterval to be 10 seconds, got %v", backOff.MaxInterval) + } + + if backOff.MaxElapsedTime != 30*time.Second { + t.Errorf("Expected MaxElapsedTime to be 30 seconds, got %v", backOff.MaxElapsedTime) + } + + if backOff.Stop != 0 { + t.Errorf("Expected Stop to be 0 (no stop), got %v", backOff.Stop) + } + + if backOff.Clock != SystemClock { + t.Errorf("Expected Clock to be SystemClock, got %v", backOff.Clock) + } +}