package retrypolicy
import (
"errors"
"fmt"
"time"
"github.com/failsafe-go/failsafe-go"
"github.com/failsafe-go/failsafe-go/policy"
)
const defaultMaxRetries = 2
var ErrExceeded = errors .New ("retries exceeded" )
type ExceededError struct {
LastResult any
LastError error
}
func (e ExceededError ) Error () string {
return fmt .Sprintf ("retries exceeded. last result: %v, last error: %v" , e .LastResult , e .LastError )
}
func (e ExceededError ) Is (err error ) bool {
if err == ErrExceeded {
return true
}
return err == e
}
func (e ExceededError ) Unwrap () error {
if e .LastError != nil {
return e .LastError
}
return fmt .Errorf ("failure: %v" , e .LastResult )
}
type RetryPolicy [R any ] interface {
failsafe .Policy [R ]
}
type RetryPolicyBuilder [R any ] interface {
failsafe .FailurePolicyBuilder [RetryPolicyBuilder [R ], R ]
failsafe .DelayablePolicyBuilder [RetryPolicyBuilder [R ], R ]
AbortOnResult (result R ) RetryPolicyBuilder [R ]
AbortOnErrors (errs ...error ) RetryPolicyBuilder [R ]
AbortOnErrorTypes (errs ...any ) RetryPolicyBuilder [R ]
AbortIf (predicate func (R , error ) bool ) RetryPolicyBuilder [R ]
ReturnLastFailure () RetryPolicyBuilder [R ]
WithMaxAttempts (maxAttempts int ) RetryPolicyBuilder [R ]
WithMaxRetries (maxRetries int ) RetryPolicyBuilder [R ]
WithMaxDuration (maxDuration time .Duration ) RetryPolicyBuilder [R ]
WithBackoff (delay time .Duration , maxDelay time .Duration ) RetryPolicyBuilder [R ]
WithBackoffFactor (delay time .Duration , maxDelay time .Duration , delayFactor float32 ) RetryPolicyBuilder [R ]
WithRandomDelay (delayMin time .Duration , delayMax time .Duration ) RetryPolicyBuilder [R ]
WithJitter (jitter time .Duration ) RetryPolicyBuilder [R ]
WithJitterFactor (jitterFactor float32 ) RetryPolicyBuilder [R ]
OnAbort (listener func (failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ]
OnRetryScheduled (listener func (failsafe .ExecutionScheduledEvent [R ])) RetryPolicyBuilder [R ]
OnRetry (listener func (failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ]
OnRetriesExceeded (listener func (failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ]
Build () RetryPolicy [R ]
}
type config[R any ] struct {
*policy .BaseFailurePolicy [R ]
*policy .BaseDelayablePolicy [R ]
*policy .BaseAbortablePolicy [R ]
returnLastFailure bool
delayMin time .Duration
delayMax time .Duration
delayFactor float32
maxDelay time .Duration
jitter time .Duration
jitterFactor float32
maxDuration time .Duration
maxRetries int
onAbort func (failsafe .ExecutionEvent [R ])
onRetry func (failsafe .ExecutionEvent [R ])
onRetryScheduled func (failsafe .ExecutionScheduledEvent [R ])
onRetriesExceeded func (failsafe .ExecutionEvent [R ])
}
var _ RetryPolicyBuilder [any ] = &config [any ]{}
type retryPolicy[R any ] struct {
*config [R ]
}
func WithDefaults [R any ]() RetryPolicy [R ] {
return Builder [R ]().Build ()
}
func Builder [R any ]() RetryPolicyBuilder [R ] {
return &config [R ]{
BaseFailurePolicy : &policy .BaseFailurePolicy [R ]{},
BaseDelayablePolicy : &policy .BaseDelayablePolicy [R ]{},
BaseAbortablePolicy : &policy .BaseAbortablePolicy [R ]{},
maxRetries : defaultMaxRetries ,
}
}
func (c *config [R ]) Build () RetryPolicy [R ] {
rpCopy := *c
return &retryPolicy [R ]{
config : &rpCopy ,
}
}
func (c *config [R ]) AbortOnResult (result R ) RetryPolicyBuilder [R ] {
c .BaseAbortablePolicy .AbortOnResult (result )
return c
}
func (c *config [R ]) AbortOnErrors (errs ...error ) RetryPolicyBuilder [R ] {
c .BaseAbortablePolicy .AbortOnErrors (errs ...)
return c
}
func (c *config [R ]) AbortOnErrorTypes (errs ...any ) RetryPolicyBuilder [R ] {
c .BaseAbortablePolicy .AbortOnErrorTypes (errs ...)
return c
}
func (c *config [R ]) AbortIf (predicate func (R , error ) bool ) RetryPolicyBuilder [R ] {
c .BaseAbortablePolicy .AbortIf (predicate )
return c
}
func (c *config [R ]) HandleErrors (errs ...error ) RetryPolicyBuilder [R ] {
c .BaseFailurePolicy .HandleErrors (errs ...)
return c
}
func (c *config [R ]) HandleErrorTypes (errs ...any ) RetryPolicyBuilder [R ] {
c .BaseFailurePolicy .HandleErrorTypes (errs ...)
return c
}
func (c *config [R ]) HandleResult (result R ) RetryPolicyBuilder [R ] {
c .BaseFailurePolicy .HandleResult (result )
return c
}
func (c *config [R ]) HandleIf (predicate func (R , error ) bool ) RetryPolicyBuilder [R ] {
c .BaseFailurePolicy .HandleIf (predicate )
return c
}
func (c *config [R ]) ReturnLastFailure () RetryPolicyBuilder [R ] {
c .returnLastFailure = true
return c
}
func (c *config [R ]) WithMaxAttempts (maxAttempts int ) RetryPolicyBuilder [R ] {
if maxAttempts == -1 {
c .maxRetries = -1
} else {
c .maxRetries = maxAttempts - 1
}
return c
}
func (c *config [R ]) WithMaxRetries (maxRetries int ) RetryPolicyBuilder [R ] {
c .maxRetries = maxRetries
return c
}
func (c *config [R ]) WithMaxDuration (maxDuration time .Duration ) RetryPolicyBuilder [R ] {
c .maxDuration = maxDuration
return c
}
func (c *config [R ]) WithDelay (delay time .Duration ) RetryPolicyBuilder [R ] {
c .BaseDelayablePolicy .WithDelay (delay )
return c
}
func (c *config [R ]) WithDelayFunc (delayFunc failsafe .DelayFunc [R ]) RetryPolicyBuilder [R ] {
c .BaseDelayablePolicy .WithDelayFunc (delayFunc )
return c
}
func (c *config [R ]) WithBackoff (delay time .Duration , maxDelay time .Duration ) RetryPolicyBuilder [R ] {
return c .WithBackoffFactor (delay , maxDelay , 2 )
}
func (c *config [R ]) WithBackoffFactor (delay time .Duration , maxDelay time .Duration , delayFactor float32 ) RetryPolicyBuilder [R ] {
c .BaseDelayablePolicy .WithDelay (delay )
c .maxDelay = maxDelay
c .delayFactor = delayFactor
c .delayMin = 0
c .delayMax = 0
return c
}
func (c *config [R ]) WithRandomDelay (delayMin time .Duration , delayMax time .Duration ) RetryPolicyBuilder [R ] {
c .delayMin = delayMin
c .delayMax = delayMax
c .Delay = 0
c .maxDelay = 0
return c
}
func (c *config [R ]) WithJitter (jitter time .Duration ) RetryPolicyBuilder [R ] {
c .jitter = jitter
return c
}
func (c *config [R ]) WithJitterFactor (jitterFactor float32 ) RetryPolicyBuilder [R ] {
c .jitterFactor = jitterFactor
return c
}
func (c *config [R ]) OnSuccess (listener func (event failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ] {
c .BaseFailurePolicy .OnSuccess (listener )
return c
}
func (c *config [R ]) OnFailure (listener func (event failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ] {
c .BaseFailurePolicy .OnFailure (listener )
return c
}
func (c *config [R ]) OnAbort (listener func (failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ] {
c .onAbort = listener
return c
}
func (c *config [R ]) OnRetry (listener func (failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ] {
c .onRetry = listener
return c
}
func (c *config [R ]) OnRetryScheduled (listener func (failsafe .ExecutionScheduledEvent [R ])) RetryPolicyBuilder [R ] {
c .onRetryScheduled = listener
return c
}
func (c *config [R ]) OnRetriesExceeded (listener func (failsafe .ExecutionEvent [R ])) RetryPolicyBuilder [R ] {
c .onRetriesExceeded = listener
return c
}
func (c *config [R ]) allowsRetries () bool {
return c .maxRetries == -1 || c .maxRetries > 0
}
func (rp *retryPolicy [R ]) ToExecutor (_ R ) any {
rpe := &executor [R ]{
BaseExecutor : &policy .BaseExecutor [R ]{
BaseFailurePolicy : rp .BaseFailurePolicy ,
},
retryPolicy : rp ,
}
rpe .Executor = rpe
return rpe
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .