Skip to Content

Resilience

The resilience package provides fault-tolerance patterns including circuit breakers, retry with exponential backoff, timeouts, and bulkhead isolation. These patterns help applications gracefully handle failures in downstream dependencies.

Import

import "github.com/gofastadev/gofasta/pkg/resilience"

Key Types

CircuitBreaker

type CircuitBreaker struct { Name string State State // Closed, Open, HalfOpen FailureCount int SuccessCount int LastFailureAt time.Time }

CircuitBreakerConfig

type CircuitBreakerConfig struct { MaxFailures int `yaml:"max_failures"` Timeout time.Duration `yaml:"timeout"` HalfOpenMax int `yaml:"half_open_max"` OnStateChange func(name string, from, to State) }

RetryConfig

type RetryConfig struct { MaxAttempts int `yaml:"max_attempts"` InitialWait time.Duration `yaml:"initial_wait"` MaxWait time.Duration `yaml:"max_wait"` Multiplier float64 `yaml:"multiplier"` Jitter bool `yaml:"jitter"` }

BulkheadConfig

type BulkheadConfig struct { MaxConcurrent int `yaml:"max_concurrent"` MaxWait time.Duration `yaml:"max_wait"` }

Key Functions

FunctionSignatureDescription
NewCircuitBreakerfunc NewCircuitBreaker(name string, cfg CircuitBreakerConfig) *CircuitBreakerCreates a new circuit breaker
Executefunc (cb *CircuitBreaker) Execute(fn func() error) errorRuns a function through the circuit breaker
Retryfunc Retry(cfg RetryConfig, fn func() error) errorRetries a function with exponential backoff
RetryWithContextfunc RetryWithContext(ctx context.Context, cfg RetryConfig, fn func(ctx context.Context) error) errorContext-aware retry
WithTimeoutfunc WithTimeout(ctx context.Context, d time.Duration, fn func(ctx context.Context) error) errorRuns a function with a deadline
NewBulkheadfunc NewBulkhead(cfg BulkheadConfig) *BulkheadCreates a concurrency limiter

Usage

Circuit Breaker

cb := resilience.NewCircuitBreaker("payment-service", resilience.CircuitBreakerConfig{ MaxFailures: 5, Timeout: 30 * time.Second, HalfOpenMax: 2, OnStateChange: func(name string, from, to resilience.State) { log.Info("circuit breaker state change", logger.F("name", name), logger.F("from", from), logger.F("to", to), ) }, }) err := cb.Execute(func() error { return paymentClient.Charge(ctx, amount) }) if err != nil { if errors.Is(err, resilience.ErrCircuitOpen) { // Circuit is open -- fail fast return errors.New("SERVICE_UNAVAILABLE", "payment service is unavailable", 503) } return err }

Retry with Exponential Backoff

err := resilience.Retry(resilience.RetryConfig{ MaxAttempts: 3, InitialWait: 100 * time.Millisecond, MaxWait: 5 * time.Second, Multiplier: 2.0, Jitter: true, }, func() error { return externalAPI.Call(ctx, payload) }) // Attempts: 100ms -> 200ms -> 400ms (with jitter)

Context-Aware Retry

err := resilience.RetryWithContext(ctx, resilience.RetryConfig{ MaxAttempts: 5, InitialWait: 200 * time.Millisecond, MaxWait: 10 * time.Second, Multiplier: 2.0, }, func(ctx context.Context) error { return db.PingContext(ctx) })

Timeout

err := resilience.WithTimeout(ctx, 5*time.Second, func(ctx context.Context) error { return slowService.Process(ctx, data) }) if err != nil { if errors.Is(err, context.DeadlineExceeded) { return errors.New("TIMEOUT", "request timed out", 504) } }

Bulkhead (Concurrency Limiter)

bulkhead := resilience.NewBulkhead(resilience.BulkheadConfig{ MaxConcurrent: 10, MaxWait: 2 * time.Second, }) err := bulkhead.Execute(func() error { return cpuIntensiveTask(data) }) if err != nil { if errors.Is(err, resilience.ErrBulkheadFull) { return errors.New("SERVICE_UNAVAILABLE", "too many concurrent requests", 503) } }

Combining Patterns

func (s *PaymentService) Charge(ctx context.Context, amount float64) error { return s.circuitBreaker.Execute(func() error { return resilience.RetryWithContext(ctx, s.retryConfig, func(ctx context.Context) error { return resilience.WithTimeout(ctx, 5*time.Second, func(ctx context.Context) error { return s.paymentClient.Charge(ctx, amount) }) }) }) }
  • Queue — Retry policies for queued jobs
  • Health — Health checks reflect circuit breaker states
  • Observability — Track resilience metrics
Last updated on