github.com/go-playground/pkg/v5@v5.29.1/errors/do.go (about) 1 //go:build go1.18 2 // +build go1.18 3 4 package errorsext 5 6 import ( 7 "context" 8 9 optionext "github.com/go-playground/pkg/v5/values/option" 10 resultext "github.com/go-playground/pkg/v5/values/result" 11 ) 12 13 // RetryableFn is a function that can be retried. 14 type RetryableFn[T, E any] func(ctx context.Context) resultext.Result[T, E] 15 16 // IsRetryableFn is called to determine if the error is retryable and optionally returns the reason for logging and metrics. 17 type IsRetryableFn[E any] func(err E) (reason string, isRetryable bool) 18 19 // OnRetryFn is called after IsRetryableFn returns true and before the retry is attempted. 20 // 21 // this allows for interception, short-circuiting and adding of backoff strategies. 22 type OnRetryFn[E any] func(ctx context.Context, originalErr E, reason string, attempt int) optionext.Option[E] 23 24 // DoRetryable will execute the provided functions code and automatically retry using the provided retry function. 25 // 26 // Deprecated: use `errorsext.Retrier` instead which corrects design issues with the current implementation. 27 func DoRetryable[T, E any](ctx context.Context, isRetryFn IsRetryableFn[E], onRetryFn OnRetryFn[E], fn RetryableFn[T, E]) resultext.Result[T, E] { 28 var attempt int 29 for { 30 result := fn(ctx) 31 if result.IsErr() { 32 err := result.Err() 33 if reason, isRetryable := isRetryFn(err); isRetryable { 34 if opt := onRetryFn(ctx, err, reason, attempt); opt.IsSome() { 35 return resultext.Err[T, E](opt.Unwrap()) 36 } 37 attempt++ 38 continue 39 } 40 } 41 return result 42 } 43 }