Resilience
The resilience package provides fault-tolerance patterns including circuit breakers and retry with exponential backoff. It uses failsafe-go under the hood. All patterns are plain Go functions — no decorators or middleware wrappers.
Import
import "github.com/gofastadev/gofasta/pkg/resilience"Key Functions
| Function | Signature | Description |
|---|---|---|
NewRetryPolicy | func NewRetryPolicy[T any](maxRetries int, delay time.Duration) retrypolicy.RetryPolicy[T] | Creates a retry policy with exponential backoff |
NewCircuitBreaker | func NewCircuitBreaker[T any](failureThreshold uint, delay time.Duration) circuitbreaker.CircuitBreaker[T] | Creates a circuit breaker that opens after a failure threshold |
Execute | func Execute[T any](fn func() (T, error), policies ...failsafe.Policy[T]) (T, error) | Runs a function with the given failsafe policies |
Usage
Retry with Exponential Backoff
retryPolicy := resilience.NewRetryPolicy[*http.Response](3, 100*time.Millisecond)
resp, err := resilience.Execute(func() (*http.Response, error) {
return externalAPI.Call(ctx, payload)
}, retryPolicy)The retry policy uses exponential backoff from delay up to delay * 10. For example, with a 100ms delay: 100ms, 200ms, 400ms, etc., capped at 1s.
Circuit Breaker
cb := resilience.NewCircuitBreaker[*PaymentResult](5, 30*time.Second)
result, err := resilience.Execute(func() (*PaymentResult, error) {
return paymentClient.Charge(ctx, amount)
}, cb)
if err != nil {
// Circuit may be open -- handle gracefully
return err
}The circuit breaker opens after failureThreshold consecutive failures and stays open for delay before transitioning to half-open.
Combining Policies
You can compose retry and circuit breaker policies together. Policies are applied in order — the innermost policy (last argument) wraps the function first.
retryPolicy := resilience.NewRetryPolicy[*PaymentResult](3, 200*time.Millisecond)
cb := resilience.NewCircuitBreaker[*PaymentResult](5, 30*time.Second)
result, err := resilience.Execute(func() (*PaymentResult, error) {
return paymentClient.Charge(ctx, amount)
}, cb, retryPolicy)Using in a Service
func (s *PaymentService) Charge(ctx context.Context, amount float64) (*PaymentResult, error) {
return resilience.Execute(func() (*PaymentResult, error) {
return s.paymentClient.Charge(ctx, amount)
}, s.circuitBreaker, s.retryPolicy)
}Related Pages
- Queue — Retry policies for queued jobs
- Health — Health checks reflect circuit breaker states
- Observability — Track resilience metrics
Last updated on