<PackageReference Include="Polly" Version="4.1.1" />

CircuitController

using Polly.Utilities; using System; namespace Polly.CircuitBreaker { internal class CircuitController : ICircuitController { private readonly TimeSpan _durationOfBreak; private readonly int _exceptionsAllowedBeforeBreaking; private int _count; private DateTime _blockedTill; private CircuitState _circuitState; private Exception _lastException; private readonly Action<Exception, TimeSpan, Context> _onBreak; private readonly Action<Context> _onReset; private readonly Action _onHalfOpen; private readonly object _lock = new object(); public CircuitState CircuitState { get { using (TimedLock.Lock(_lock)) { if (_circuitState == CircuitState.Open && !IsInAutomatedBreak) { _circuitState = CircuitState.HalfOpen; _onHalfOpen(); } return _circuitState; } } } public Exception LastException { get { using (TimedLock.Lock(_lock)) return _lastException; } } public bool IsInAutomatedBreak { get { using (TimedLock.Lock(_lock)) return SystemClock.UtcNow() < _blockedTill; } } public CircuitController(int exceptionsAllowedBeforeBreaking, TimeSpan durationOfBreak, Action<Exception, TimeSpan, Context> onBreak, Action<Context> onReset, Action onHalfOpen) { _durationOfBreak = durationOfBreak; _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; _onBreak = onBreak; _onReset = onReset; _onHalfOpen = onHalfOpen; ResetInternal_NeedsLock(); } public void Isolate() { using (TimedLock.Lock(_lock)) { _lastException = new IsolatedCircuitException("The circuit is manually held open and is not allowing calls."); BreakFor_NeedsLock(TimeSpan.MaxValue, Context.Empty); _circuitState = CircuitState.Isolated; } } private void ResetInternal_NeedsLock() { _count = 0; _blockedTill = DateTime.MinValue; _circuitState = CircuitState.Closed; _lastException = new InvalidOperationException("This exception should never be thrown"); } public void Reset() { Reset(Context.Empty); } private void Reset(Context context) { using (TimedLock.Lock(_lock)) { ResetInternal_NeedsLock(); _onReset(context ?? Context.Empty); } } public void OnActionSuccess(Context context) { Reset(context); } public void OnActionFailure(Exception ex, Context context) { using (TimedLock.Lock(_lock)) { _lastException = ex; _count++; if (_count >= _exceptionsAllowedBeforeBreaking) BreakFor_NeedsLock(_durationOfBreak, context); } } private void BreakFor_NeedsLock(TimeSpan durationOfBreak, Context context) { _blockedTill = ((durationOfBreak > DateTime.MaxValue - SystemClock.UtcNow()) ? DateTime.MaxValue : (SystemClock.UtcNow() + durationOfBreak)); _circuitState = CircuitState.Open; _onBreak(_lastException, durationOfBreak, context ?? Context.Empty); } } }