DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
HardMachine Coding

Implement a Circuit Breaker Pattern

43 views

Problem Statement

At Netflix, when a downstream service is unhealthy, we need to fail fast instead of waiting for timeouts. Implement a Circuit Breaker that prevents cascading failures in distributed systems.

Circuit Breaker States


       ┌─────────────────────────────────────────────────┐
       │                                                 │
       ▼                                                 │
   ┌───────┐   failures > threshold   ┌────────┐       │
   │CLOSED │ ───────────────────────► │  OPEN  │       │
   │(Normal)│                         │(Failing)│       │
   └───┬───┘                          └────┬───┘       │
       │                                   │            │
       │ success                  timeout expires      │
       │                                   │            │
       │         ┌───────────┐             │            │
       └─────────│ HALF-OPEN │◄────────────┘            │
                 │ (Testing) │                          │
                 └─────┬─────┘                          │
                       │                                │
                       │ success: reset                 │
                       │ failure: back to open ─────────┘
                       ▼

Implementation

package circuitbreaker

import (
    "errors"
    "sync"
    "time"
)

type State int

const (
    StateClosed State = iota
    StateOpen
    StateHalfOpen
)

var ErrCircuitOpen = errors.New("circuit breaker is open")

type CircuitBreaker struct {
    mu sync.RWMutex
    
    state          State
    failureCount   int
    successCount   int
    lastFailure    time.Time
    
    maxFailures    int           // Failures before opening
    timeout        time.Duration // Time to wait before half-open
    halfOpenMax    int           // Successes needed to close
}

func New(maxFailures int, timeout time.Duration) *CircuitBreaker {
    return &CircuitBreaker{
        state:       StateClosed,
        maxFailures: maxFailures,
        timeout:     timeout,
        halfOpenMax: 3,
    }
}

func (cb *CircuitBreaker) Execute(fn func() error) error {
    if !cb.allowRequest() {
        return ErrCircuitOpen
    }
    
    err := fn()
    
    cb.recordResult(err)
    return err
}

func (cb *CircuitBreaker) allowRequest() bool {
    cb.mu.Lock()
    defer cb.mu.Unlock()
    
    switch cb.state {
    case StateClosed:
        return true
        
    case StateOpen:
        if time.Since(cb.lastFailure) > cb.timeout {
            cb.state = StateHalfOpen
            cb.successCount = 0
            return true
        }
        return false
        
    case StateHalfOpen:
        return true
    }
    
    return false
}

func (cb *CircuitBreaker) recordResult(err error) {
    cb.mu.Lock()
    defer cb.mu.Unlock()
    
    if err != nil {
        cb.onFailure()
    } else {
        cb.onSuccess()
    }
}

func (cb *CircuitBreaker) onSuccess() {
    switch cb.state {
    case StateClosed:
        cb.failureCount = 0
        
    case StateHalfOpen:
        cb.successCount++
        if cb.successCount >= cb.halfOpenMax {
            cb.state = StateClosed
            cb.failureCount = 0
        }
    }
}

func (cb *CircuitBreaker) onFailure() {
    cb.lastFailure = time.Now()
    
    switch cb.state {
    case StateClosed:
        cb.failureCount++
        if cb.failureCount >= cb.maxFailures {
            cb.state = StateOpen
        }
        
    case StateHalfOpen:
        cb.state = StateOpen
    }
}

func (cb *CircuitBreaker) State() State {
    cb.mu.RLock()
    defer cb.mu.RUnlock()
    return cb.state
}

Usage Example

func main() {
    cb := circuitbreaker.New(5, 30*time.Second)
    
    client := &http.Client{Timeout: 5 * time.Second}
    
    for i := 0; i < 100; i++ {
        err := cb.Execute(func() error {
            resp, err := client.Get("https://unreliable-service.com/api")
            if err != nil {
                return err
            }
            defer resp.Body.Close()
            
            if resp.StatusCode >= 500 {
                return fmt.Errorf("server error: %d", resp.StatusCode)
            }
            return nil
        })
        
        if errors.Is(err, circuitbreaker.ErrCircuitOpen) {
            log.Println("Circuit is open, using fallback")
            useFallback()
        } else if err != nil {
            log.Println("Request failed:", err)
        }
    }
}

Production Library

// Use github.com/sony/gobreaker in production
import "github.com/sony/gobreaker"

cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
    Name:        "payment-service",
    MaxRequests: 3,
    Interval:    10 * time.Second,
    Timeout:     30 * time.Second,
    ReadyToTrip: func(counts gobreaker.Counts) bool {
        return counts.ConsecutiveFailures > 5
    },
})

Follow-up Questions

  1. How do you implement per-endpoint circuit breakers?
  2. How do you share circuit breaker state across instances?
  3. What metrics would you expose for monitoring?

Sample Test Cases

Case 1
Input
threshold=3, timeout=5s, requests=[success, success, fail, fail, fail]
Expected Output
Circuit opens after 3 consecutive failures
Case 2
Input
[]
Expected Output
null
Case 3
Input
["closed_to_open_then_half_open", 3, 100]
Expected Output
["success", "success", "failure", "failure", "failure", "open_error", "open_error", "half_open_success", "success", "success", "success"]
Case 4
Input
["half_open_to_open_on_failure", 2, 100]
Expected Output
["success", "failure", "failure", "open_error", "open_error", "half_open_failure", "open_error", "open_error"]
Case 5
Input
[]
Expected Output
null
Case 6
Input
threshold=3, state=open, wait=5s
Expected Output
Circuit transitions to half-open after timeout
Case 7
Input
["initial_half_open_success_resets", 1, 100]
Expected Output
["failure", "open_error", "open_error", "half_open_success", "success", "success"]
Case 8
Input
[]
Expected Output
null

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
43
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go