Type Safety
Failsafe-go’s APIs are typed based on the expected execution result. For some policies and executions, this type may not matter:
retryPolicy := retrypolicy.NewWithDefaults[any]()
err := failsafe.With(retryPolicy).Run(Connect)
But for other cases you might declare a more specific result type:
retryPolicy := retrypolicy.NewBuilder[*http.Response]().
HandleIf(func(response *http.Response, err error) bool {
return response != nil && response.StatusCode == 500
}).
OnFailure(func(e failsafe.ExecutionEvent[*http.Response]) {
logger.Error("Failed attempt", "statusCode", e.LastResult().StatusCode)
}).
Build()
This allows Failsafe-go to ensure that the same result type used for the policy is returned by the execution and is available in event listeners:
response, err := failsafe.With(retryPolicy).
OnSuccess(func(e failsafe.ExecutionDoneEvent[*http.Response]) {
logger.Info("Request sent", "statusCode", e.Result.StatusCode)
}).
Get(SendHttpRequest)
It also ensures that when multiple policies are composed, they all share the same result type:
circuitBreaker := circuitbreaker.NewWithDefaults[*http.Response]()
response, err := failsafe.With(retryPolicy, circuitBreaker).Get(SendHttpRequest)
Mixing Result Types
When composing shared policies, it’s common for the shared policy to have any
as the result type. These can be composed inside policies with specific result types:
circuitBreaker := circuitbreaker.NewWithDefaults[any]()
retryPolicy := retrypolicy.NewWithDefaults[Connection]()
// Compose RetryPolicy[Connection] around CircuitBreaker[any]
failsafe.With(retryPolicy).ComposeAny(circuitBreaker)
Or they can be composed outside other policies:
// Compose CircuitBreaker[any] around RetryPolicy[Connection]
failsafe.WithAny[Connection](circuitBreaker).Compose(retryPolicy)