33
44package conman
55
6+ import "fmt"
7+
68// RetryConfig defines the retry behavior for operations that may fail temporarily.
79// It includes parameters for controlling the number of attempts, delays, and backoff strategy.
810type RetryConfig struct {
@@ -13,6 +15,33 @@ type RetryConfig struct {
1315 Jitter bool // Whether to add random jitter to delays
1416}
1517
18+ // validate checks the validity of the RetryConfig fields.
19+ // It ensures that all parameters have valid values and logical relationships.
20+ // Returns an error if any validation fails, otherwise returns nil.
21+ func (rc * RetryConfig ) validate () error {
22+ if rc .MaxAttempts <= 0 {
23+ return fmt .Errorf ("MaxAttempts must be positive, got %d" , rc .MaxAttempts )
24+ }
25+ if rc .InitialDelay < 0 {
26+ return fmt .Errorf ("InitialDelay cannot be negative, got %d" , rc .InitialDelay )
27+ }
28+ if rc .MaxDelay < 0 {
29+ return fmt .Errorf ("MaxDelay cannot be negative, got %d" , rc .MaxDelay )
30+ }
31+ if rc .MaxDelay > 0 && rc .InitialDelay > rc .MaxDelay {
32+ return fmt .Errorf ("InitialDelay (%d) cannot be greater than MaxDelay (%d)" ,
33+ rc .InitialDelay , rc .MaxDelay )
34+ }
35+ if rc .BackoffFactor < 0 {
36+ return fmt .Errorf ("BackoffFactor cannot be negative, got %f" , rc .BackoffFactor )
37+ }
38+ if rc .BackoffFactor == 0.0 && rc .InitialDelay > 0 && rc .MaxAttempts > 1 {
39+ // This creates immediate zero delays after first attempt
40+ return fmt .Errorf ("BackoffFactor of 0.0 with non-zero InitialDelay will result in zero delays" )
41+ }
42+ return nil
43+ }
44+
1645// RetriableError is an error type that indicates a task should be retried.
1746// It includes an embedded RetryConfig to specify the retry strategy.
1847type RetriableError struct {
@@ -25,72 +54,49 @@ func (e *RetriableError) Error() string {
2554 return e .Err .Error ()
2655}
2756
28- // WithExponentialBackoff configures the error to use exponential backoff retry strategy.
29- // Returns the RetriableError for method chaining.
30- func (e * RetriableError ) WithExponentialBackoff () * RetriableError {
31- e .RetryConfig = ExponentialBackoffRetryPolicy {}.RetryConfig ()
32- return e
33- }
34-
35- // WithLinearBackoff configures the error to use linear backoff retry strategy.
36- // Returns the RetriableError for method chaining.
37- func (e * RetriableError ) WithLinearBackoff () * RetriableError {
38- e .RetryConfig = LinearBackoffRetryPolicy {}.RetryConfig ()
39- return e
57+ func (e * RetriableError ) WithRetryConfig (config * RetryConfig ) (* RetriableError , error ) {
58+ if err := config .validate (); err != nil {
59+ return nil , err
60+ }
61+ e .RetryConfig = config
62+ return e , nil
4063}
4164
42- // WithNoBackoff configures the error to use immediate retries without delays .
65+ // WithExponentialBackoff configures the error to use exponential backoff retry strategy .
4366// Returns the RetriableError for method chaining.
44- func (e * RetriableError ) WithNoBackoff () * RetriableError {
45- e .RetryConfig = NoBackoffRetryPolicy {}.RetryConfig ()
46- return e
47- }
48-
49- // RetryPolicy defines an interface for different retry strategies.
50- type RetryPolicy interface {
51- RetryConfig () * RetryConfig
52- }
53-
54- // ExponentialBackoffRetryPolicy implements exponential backoff with jitter.
55- // Delays increase exponentially with each retry attempt.
56- type ExponentialBackoffRetryPolicy struct {}
57-
58- // RetryConfig returns the retry configuration for exponential backoff.
59- func (e ExponentialBackoffRetryPolicy ) RetryConfig () * RetryConfig {
60- return & RetryConfig {
67+ func (e * RetriableError ) WithExponentialBackoff () * RetriableError {
68+ e .RetryConfig = & RetryConfig {
6169 MaxAttempts : 5 ,
6270 InitialDelay : 100 , // 100 milliseconds
6371 BackoffFactor : 2.0 ,
6472 MaxDelay : 5000 , // 5 seconds
6573 Jitter : true ,
6674 }
75+ return e
6776}
6877
69- // LinearBackoffRetryPolicy implements linear backoff.
70- // Delays increase linearly with each retry attempt.
71- type LinearBackoffRetryPolicy struct {}
72-
73- // RetryConfig returns the retry configuration for linear backoff.
74- func (l LinearBackoffRetryPolicy ) RetryConfig () * RetryConfig {
75- return & RetryConfig {
78+ // WithLinearBackoff configures the error to use linear backoff retry strategy.
79+ // Returns the RetriableError for method chaining.
80+ func (e * RetriableError ) WithLinearBackoff () * RetriableError {
81+ e .RetryConfig = & RetryConfig {
7682 MaxAttempts : 5 ,
7783 InitialDelay : 200 , // 200 milliseconds
7884 BackoffFactor : 1.0 ,
7985 MaxDelay : 2000 , // 2 seconds
8086 Jitter : false ,
8187 }
88+ return e
8289}
8390
84- // NoBackoffRetryPolicy implements immediate retries without delays.
85- type NoBackoffRetryPolicy struct {}
86-
87- // RetryConfig returns the retry configuration for immediate retries.
88- func (n NoBackoffRetryPolicy ) RetryConfig () * RetryConfig {
89- return & RetryConfig {
91+ // WithNoBackoff configures the error to use immediate retries without delays.
92+ // Returns the RetriableError for method chaining.
93+ func (e * RetriableError ) WithNoBackoff () * RetriableError {
94+ e .RetryConfig = & RetryConfig {
9095 MaxAttempts : 3 ,
9196 InitialDelay : 0 ,
9297 BackoffFactor : 0.0 ,
9398 MaxDelay : 0 ,
9499 Jitter : false ,
95100 }
101+ return e
96102}
0 commit comments