@@ -180,14 +180,21 @@ func DoWithData[T any](retryableFunc RetryableFuncWithData[T], opts ...Option) (
180180 }
181181 attempt ++
182182
183- // Wait for next attempt
184- delayDuration := delay (config , attempt , err )
183+ // Wait for next attempt - inline delay calculation for performance
184+ delayTime := config .delayType (attempt , err , config )
185+ if delayTime < 0 {
186+ delayTime = 0
187+ }
188+ if config .maxDelay > 0 && delayTime > config .maxDelay {
189+ delayTime = config .maxDelay
190+ }
191+
185192 select {
186- case <- config .timer .After (delayDuration ):
193+ case <- config .timer .After (delayTime ):
187194 case <- config .context .Done ():
188195 contextErr := context .Cause (config .context )
189196 if config .lastErrorOnly {
190- if config .wrapContextErrorWithLastError && err != nil {
197+ if config .wrapLastErr && err != nil {
191198 return emptyT , fmt .Errorf ("%w: %w" , contextErr , err )
192199 }
193200 return emptyT , contextErr
@@ -228,14 +235,25 @@ type Error []error
228235// Error returns a string representation of all errors that occurred during retry attempts.
229236// Each error is prefixed with its attempt number.
230237func (e Error ) Error () string {
231- logWithNumber := make ([]string , len (e ))
238+ if len (e ) == 0 {
239+ return "All attempts fail:"
240+ }
241+
242+ // Use strings.Builder for efficient string concatenation
243+ var b strings.Builder
244+ b .WriteString ("All attempts fail:" )
245+
232246 for i , err := range e {
233247 if err != nil {
234- logWithNumber [i ] = fmt .Sprintf ("#%d: %s" , i + 1 , err .Error ())
248+ b .WriteByte ('\n' )
249+ b .WriteByte ('#' )
250+ b .WriteString (fmt .Sprint (i + 1 ))
251+ b .WriteString (": " )
252+ b .WriteString (err .Error ())
235253 }
236254 }
237-
238- return fmt . Sprintf ( "All attempts fail: \n %s" , strings . Join ( logWithNumber , " \n " ) )
255+
256+ return b . String ( )
239257}
240258
241259// Is reports whether any error in e matches target.
@@ -315,30 +333,14 @@ func IsRecoverable(err error) bool {
315333// Is implements error matching for unrecoverableError.
316334// It supports errors.Is by checking if the target is also an unrecoverableError.
317335func (unrecoverableError ) Is (err error ) bool {
318- _ , isUnrecoverable := err .(unrecoverableError )
319- return isUnrecoverable
336+ _ , ok := err .(unrecoverableError )
337+ return ok
320338}
321339
322340func unpackUnrecoverable (err error ) error {
323- if unrecoverable , isUnrecoverable := err .(unrecoverableError ); isUnrecoverable {
324- return unrecoverable .error
341+ if u , ok := err .(unrecoverableError ); ok {
342+ return u .error
325343 }
326-
327344 return err
328345}
329346
330- func delay (config * Config , attempt uint , err error ) time.Duration {
331- delayTime := config .delayType (attempt , err , config )
332-
333- // Ensure delay is non-negative
334- if delayTime < 0 {
335- delayTime = 0
336- }
337-
338- // Apply max delay cap if configured
339- if config .maxDelay > 0 && delayTime > config .maxDelay {
340- delayTime = config .maxDelay
341- }
342-
343- return delayTime
344- }
0 commit comments