Graceful degradation is a resilience pattern where the system continues to work when dependencies fail.
1// Circuit breaker + fallback2import "github.com/sony/gobreaker"34type UserService struct {5 db *sql.DB6 cache *redis.Client7 cb *gobreaker.CircuitBreaker8}910func (s *UserService) GetUser(id int) (*User, error) {11 // 1. Try from cache12 if user, err := s.cacheGet(id); err == nil {13 return user, nil14 }1516 // 2. Try from DB via circuit breaker17 result, err := s.cb.Execute(func() (interface{}, error) {18 return s.dbGet(id)19 })2021 if err != nil {22 // 3. Fallback: stale data from cache23 if user, err := s.cacheGetStale(id); err == nil {24 return user, nil25 }2627 // 4. Ultimate fallback: default data28 return &User{ID: id, Name: "Unknown"}, nil29 }3031 user := result.(*User)32 s.cacheSet(id, user) // Cache it33 return user, nil34}3536// Retry with exponential backoff37import "github.com/cenkalti/backoff"3839func callWithRetry(fn func() error) error {40 expBackoff := backoff.NewExponentialBackOff()41 expBackoff.MaxElapsedTime = 30 * time.Second4243 return backoff.Retry(fn, expBackoff)44}4546// Timeout for each service47func fetchWithTimeout(url string, timeout time.Duration) ([]byte, error) {48 ctx, cancel := context.WithTimeout(context.Background(), timeout)49 defer cancel()5051 req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)52 resp, err := http.DefaultClient.Do(req)53 if err != nil {54 return nil, err55 }56 defer resp.Body.Close()57 return io.ReadAll(resp.Body)58}
Strategies: