Execute runs the given function with circuit breaker protection
(fn func() error)
| 92 | |
| 93 | // Execute runs the given function with circuit breaker protection |
| 94 | func (cb *CircuitBreaker) Execute(fn func() error) error { |
| 95 | // Single atomic state load for consistency |
| 96 | state := CircuitBreakerState(cb.state.Load()) |
| 97 | |
| 98 | switch state { |
| 99 | case CircuitBreakerOpen: |
| 100 | if cb.shouldAttemptReset() { |
| 101 | // Attempt transition to half-open |
| 102 | if cb.state.CompareAndSwap(int32(CircuitBreakerOpen), int32(CircuitBreakerHalfOpen)) { |
| 103 | cb.requests.Store(0) |
| 104 | cb.successes.Store(0) |
| 105 | if internal.LogLevel.InfoOrAbove() { |
| 106 | internal.Logger.Printf(context.Background(), logs.CircuitBreakerTransitioningToHalfOpen(cb.endpoint)) |
| 107 | } |
| 108 | // Fall through to half-open logic |
| 109 | } else { |
| 110 | return ErrCircuitBreakerOpen |
| 111 | } |
| 112 | } else { |
| 113 | return ErrCircuitBreakerOpen |
| 114 | } |
| 115 | fallthrough |
| 116 | case CircuitBreakerHalfOpen: |
| 117 | requests := cb.requests.Add(1) |
| 118 | if requests > int64(cb.maxRequests) { |
| 119 | cb.requests.Add(-1) // Revert the increment |
| 120 | return ErrCircuitBreakerOpen |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | // Execute the function with consistent state |
| 125 | err := fn() |
| 126 | |
| 127 | if err != nil { |
| 128 | cb.recordFailure() |
| 129 | return err |
| 130 | } |
| 131 | |
| 132 | cb.recordSuccess() |
| 133 | return nil |
| 134 | } |
| 135 | |
| 136 | // recordFailure records a failure and potentially opens the circuit |
| 137 | func (cb *CircuitBreaker) recordFailure() { |