Exercise: Circuit Breaker Patterns
Difficulty - Advanced
Learning Objectives
- Apply circuit breaker concepts from distributed systems
- Implement advanced circuit breaker configurations
- Practice with monitoring and observability integration
- Understand production circuit breaker patterns
Problem Statement
This exercise builds upon the comprehensive circuit breaker coverage in Distributed Systems Patterns. Instead of reimplementing the core circuit breaker, you'll apply it to advanced scenarios and integrate it with production systems.
📖 Background: For detailed explanations of circuit breaker concepts, state transitions, and production considerations, see the Circuit Breaker section in the Distributed Systems tutorial.
Exercise Tasks
Task 1: Integrate Circuit Breaker with External Services
Using the circuit breaker implementation from the Distributed Systems article, implement a resilient HTTP client:
1package main
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7 "time"
8)
9
10// Exercise: Build a resilient HTTP client using the CircuitBreaker from
11// /03-advanced-topics/15-distributed-systems
12
13type ResilientHTTPClient struct {
14 client *http.Client
15 cb *CircuitBreaker
16}
17
18func NewResilientHTTPClient(timeout time.Duration) *ResilientHTTPClient {
19 // TODO: Create circuit breaker with appropriate settings
20 // TODO: Configure HTTP client with timeouts
21 return &ResilientHTTPClient{}
22}
23
24// TODO: Implement HTTP call with circuit breaker protection
25func Get(ctx context.Context, url string) {
26 // 1. Check circuit breaker state
27 // 2. Execute HTTP call through circuit breaker
28 // 3. Handle errors and fallback responses
29 // 4. Return appropriate responses for open circuit
30}
31
32func main() {
33 client := NewResilientHTTPClient(10 * time.Second)
34
35 // TODO: Test the client with various scenarios
36 // - Normal operation
37 // - Service failures
38 // - Circuit opening
39 // - Recovery scenarios
40
41 fmt.Println("Resilient HTTP client implementation")
42}
Task 2: Multi-Service Circuit Breaker Management
Implement a circuit breaker manager for multiple services:
1// Exercise: Build a manager for multiple circuit breakers
2type CircuitBreakerManager struct {
3 breakers map[string]*CircuitBreaker
4 mu sync.RWMutex
5}
6
7// TODO: Implement methods for:
8// - Creating circuit breakers per service
9// - Monitoring all circuit breakers
10// - Handling cascading failures
11// - Providing dashboards/alerts
12func CallService(ctx context.Context, serviceName string, fn func() error) error {
13 // TODO: Get or create circuit breaker for service
14 // TODO: Execute function through circuit breaker
15 // TODO: Handle service-specific configurations
16}
Task 3: Observability Integration
Extend the circuit breaker with comprehensive monitoring:
1// Exercise: Add metrics and distributed tracing
2type ObservableCircuitBreaker struct {
3 *CircuitBreaker
4 metrics CircuitBreakerMetrics
5 tracer opentelemetry.Tracer
6}
7
8// TODO: Implement:
9// - Prometheus metrics for state changes
10// - OpenTelemetry tracing for calls
11// - Health check endpoints
12// - Alerting on state transitions
Task 4: Production Scenarios
Apply the circuit breaker patterns to these scenarios:
- Database Connection Pooling: Prevent cascade when database fails
- External API Calls: Handle third-party service outages
- Microservices Communication: Protect against service failures
- Message Queue Processing: Handle broker connectivity issues
Hint: Reference Implementation
The core circuit breaker implementation is available in the Distributed Systems article:
1// From /03-advanced-topics/15-distributed-systems
2type CircuitBreaker struct {
3 mu sync.Mutex
4 state State
5 failureCount int
6 maxFailures int
7 timeout time.Duration
8 lastFailureTime time.Time
9}
10
11func Call(fn func() error) error
12func State() State
For advanced patterns including metrics, distributed circuit breakers, and production considerations, see the main article.
Solution Approach
Implementation Guidelines
Task 1 Solution:
1func NewResilientHTTPClient(timeout time.Duration) *ResilientHTTPClient {
2 settings := Settings{
3 MaxRequests: 5,
4 Interval: time.Minute,
5 Timeout: 30 * time.Second,
6 ReadyToTrip: func(counts Counts) bool {
7 failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
8 return counts.Requests >= 5 && failureRatio >= 0.5
9 },
10 OnStateChange: func(from, to State) {
11 log.Printf("Circuit breaker %s -> %s", from, to)
12 },
13 }
14
15 return &ResilientHTTPClient{
16 client: &http.Client{Timeout: timeout},
17 cb: New("http-client", settings),
18 }
19}
20
21func Get(ctx context.Context, url string) {
22 var resp *http.Response
23 err := c.cb.Call(ctx, func() error {
24 req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
25 if err != nil {
26 return err
27 }
28
29 resp, err = c.client.Do(req)
30 return err
31 })
32
33 if err != nil {
34 return nil, fmt.Errorf("circuit breaker error: %w", err)
35 }
36
37 return resp, nil
38}
Task 2 Solution:
1func CallService(ctx context.Context, serviceName string, fn func() error) error {
2 m.mu.RLock()
3 cb, exists := m.breakers[serviceName]
4 m.mu.RUnlock()
5
6 if !exists {
7 m.mu.Lock()
8 cb, exists = m.breakers[serviceName]
9 if !exists {
10 cb = m.createCircuitBreaker(serviceName)
11 m.breakers[serviceName] = cb
12 }
13 m.mu.Unlock()
14 }
15
16 return cb.Call(ctx, fn)
17}
18
19func createCircuitBreaker(serviceName string) *CircuitBreaker {
20 settings := Settings{
21 MaxRequests: 3,
22 Interval: time.Minute,
23 Timeout: 15 * time.Second,
24 ReadyToTrip: func(counts Counts) bool {
25 return counts.ConsecutiveFailures >= 3
26 },
27 OnStateChange: func(from, to State) {
28 log.Printf("Service %s circuit breaker: %s -> %s", serviceName, from, to)
29 },
30 }
31
32 return New(serviceName, settings)
33}
Key Takeaways
- Circuit breakers prevent cascading failures in distributed systems
- Configuration must be tuned for each service's characteristics
- Observability is crucial for monitoring circuit breaker health
- Multiple circuit breakers require careful management to avoid coordination failures
- Production systems need sophisticated fallback and recovery strategies
Further Learning
For comprehensive coverage of circuit breaker patterns including:
- Detailed state transition logic
- Advanced patterns
- Production best practices and pitfalls
- Integration with observability platforms
- Benchmarking and performance optimization
See: Distributed Systems Patterns → Circuit Breaker
For cloud-native circuit breaker implementations, see:
Additional Challenges
- Adaptive Thresholds: Implement circuit breakers that adjust thresholds based on service performance
- Distributed Coordination: Build circuit breakers that coordinate across multiple instances
- Machine Learning Integration: Use ML to predict optimal circuit breaker configurations
- Chaos Engineering: Design experiments to test circuit breaker effectiveness under failure conditions