@@ -104,42 +104,62 @@ type RetryOptions struct {
104104
105105// WithRetry returns a function with retry logic for execution.
106106// It makes the specified number of attempts to call fn until it succeeds.
107- // Before the first attempt, it waits for the specified Delay.
107+ // Between attempts, it waits for the specified Delay using a ticker.
108+ // The function respects context cancellation and will return context.Err() if done.
109+ //
110+ // Behavior:
111+ // - If Attempts = 0, the function immediately returns nil without executing fn
112+ // - Before each attempt, it waits for the Delay period
113+ // - The function stops retrying on first successful execution
114+ // - Context cancellation is respected between attempts
115+ // - All errors from failed attempts are collected
116+ //
108117// If all attempts fail, behavior depends on ReturnAllAroseErr:
109- // - if true - returns all errors via `errors.Join(...)`.
110- // - if false - returns the lat error.
118+ // - if true - returns all errors via errors.Join(...)
119+ // - if false - returns only the last error that occurred
120+ //
121+ // Example:
122+ //
123+ // opts := RetryOptions{
124+ // Attempts: 3,
125+ // Delay: time.Second,
126+ // ReturnAllAroseErr: true,
127+ // }
128+ //
129+ // retryableFn := WithRetry(opts, func(ctx context.Context) error {
130+ // return someOperation(ctx)
131+ // })
111132//
112- // If Attempts = 0, the function immediately returns nil without executing fn.
133+ // err := retryableFn(ctx) // Will try up to 3 times with 1s delays
113134func WithRetry (opt RetryOptions , fn func (ctx context.Context ) error ) func (ctx context.Context ) error {
114135 return func (ctx context.Context ) error {
115136 if opt .Attempts == 0 {
116137 return nil
117138 }
118139
119- time .Sleep (opt .Delay )
120-
121140 var (
122141 err error
123142 retryErr []error
124- i = 0
143+ ticker = time . NewTicker ( opt . Delay )
125144 )
126- for ; i < int (opt .Attempts ); i ++ {
127- err = fn (ctx )
128- if err == nil {
129- break
145+ defer ticker .Stop ()
146+
147+ for i := uint32 (0 ); i < opt .Attempts ; i ++ {
148+ select {
149+ case <- ctx .Done ():
150+ return ctx .Err ()
151+ case <- ticker .C :
152+ err = fn (ctx )
153+ if err == nil {
154+ break
155+ }
156+ retryErr = append (retryErr , fmt .Errorf ("retry [%d]: %w" , i , err ))
130157 }
131-
132- retryErr = append (retryErr , fmt .Errorf ("retry [%d]: %w" , i , err ))
133- }
134-
135- if len (retryErr ) == 0 {
136- return nil
137158 }
138159
139160 if opt .ReturnAllAroseErr {
140161 return errors .Join (retryErr ... )
141162 }
142-
143163 return err
144164 }
145165}
0 commit comments