package circuitbreaker import ( "errors" "sync" "time" ) // State represents the state of the circuit breaker type State int const ( StateClosed State = iota StateOpen StateHalfOpen ) func (s State) String() string { switch s { case StateClosed: return "Closed" case StateOpen: return "Open" case StateHalfOpen: return "HalfOpen" default: return "Unknown" } } // CircuitBreaker implements the circuit breaker pattern type CircuitBreaker struct { mu sync.Mutex state State failureCount uint failureThreshold uint successThreshold uint timeout time.Duration lastFailureTime time.Time halfOpenSuccesses uint } // Config holds the configuration for the circuit breaker type Config struct { FailureThreshold uint SuccessThreshold uint Timeout time.Duration } // NewCircuitBreaker creates a new circuit breaker with the given configuration func NewCircuitBreaker(config Config) *CircuitBreaker { return &CircuitBreaker{ state: StateClosed, failureThreshold: config.FailureThreshold, successThreshold: config.SuccessThreshold, timeout: config.Timeout, } } // DefaultConfig returns a default configuration for the circuit breaker func DefaultConfig() Config { return Config{ FailureThreshold: 5, SuccessThreshold: 2, Timeout: 60 * time.Second, } } // Execute runs the given function with circuit breaker protection func (cb *CircuitBreaker) Execute(fn func() error) error { cb.mu.Lock() // Check if we should attempt to transition from Open to HalfOpen if cb.state == StateOpen && time.Since(cb.lastFailureTime) > cb.timeout { cb.state = StateHalfOpen cb.halfOpenSuccesses = 0 } // If circuit is open, reject the request if cb.state == StateOpen { cb.mu.Unlock() return errors.New("circuit breaker is open") } cb.mu.Unlock() // Execute the function err := fn() cb.mu.Lock() defer cb.mu.Unlock() if err != nil { cb.onFailure() return err } cb.onSuccess() return nil } // onFailure handles a failed operation func (cb *CircuitBreaker) onFailure() { cb.failureCount++ cb.lastFailureTime = time.Now() if cb.failureCount >= cb.failureThreshold { cb.state = StateOpen } } // onSuccess handles a successful operation func (cb *CircuitBreaker) onSuccess() { if cb.state == StateClosed { cb.failureCount = 0 return } if cb.state == StateHalfOpen { cb.halfOpenSuccesses++ if cb.halfOpenSuccesses >= cb.successThreshold { cb.state = StateClosed cb.failureCount = 0 } } } // GetState returns the current state of the circuit breaker func (cb *CircuitBreaker) GetState() State { cb.mu.Lock() defer cb.mu.Unlock() return cb.state } // Reset resets the circuit breaker to closed state func (cb *CircuitBreaker) Reset() { cb.mu.Lock() defer cb.mu.Unlock() cb.state = StateClosed cb.failureCount = 0 cb.halfOpenSuccesses = 0 }