Created
November 14, 2009 03:16
-
-
Save dvhthomas/234358 to your computer and use it in GitHub Desktop.
Circuit Breaker implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Timers; | |
namespace CityIQ.HealthMonitor | |
{ | |
/// <summary> | |
/// Intercepts calls to brittle or problematic resources | |
/// and maintains state of the resource using a circuit breaker | |
/// analogy. A closed circuit is good, and open circuit is bad because | |
/// it means that the resource being called is not responding within | |
/// the allotted time span. | |
/// </summary> | |
/// <remarks>Apart from removing Castle Windsor Interceptor dependencies | |
/// and going with an Action instead, this is verbatim from an excellent | |
/// implementation by Davy Brion: http://davybrion.com/blog/2009/07/protecting-your-application-from-remote-problems/</remarks> | |
public class CircuitBreaker : ICircuitBreaker | |
{ | |
private readonly object _monitor = new object(); | |
private int _failures; | |
private CircuitBreakerState _state; | |
private TimeSpan _timeout; | |
private readonly int _threshold; | |
public CircuitBreaker(int threshold, TimeSpan timeout) | |
{ | |
_threshold = threshold; | |
_timeout = timeout; | |
MoveToClosedState(); | |
} | |
public int Failures | |
{ | |
get { return _failures; } | |
} | |
#region IInterceptor Members | |
public void ExecuteCall<T>(T invoker,Action<T> action) | |
{ | |
using (TimedLock.Lock(_monitor)) | |
{ | |
_state.ProtectedCodeIsAboutToBeCalled(); | |
} | |
try | |
{ | |
action.Invoke(invoker); | |
} | |
catch (Exception e) | |
{ | |
using (TimedLock.Lock(_monitor)) | |
{ | |
_failures = Failures + 1; | |
_state.ActUponException(e); | |
} | |
throw; | |
} | |
using (TimedLock.Lock(_monitor)) | |
{ | |
_state.ProtectedCodeHasBeenCalled(); | |
} | |
} | |
#endregion | |
private void MoveToClosedState() | |
{ | |
_state = new ClosedState(this); | |
} | |
private void MoveToOpenState() | |
{ | |
_state = new OpenState(this); | |
} | |
private void MoveToHalfOpenState() | |
{ | |
_state = new HalfOpenState(this); | |
} | |
private void ResetFailureCount() | |
{ | |
_failures = 0; | |
} | |
private bool ThresholdReached() | |
{ | |
return Failures >= _threshold; | |
} | |
#region Nested type: CircuitBreakerState | |
private abstract class CircuitBreakerState | |
{ | |
protected readonly CircuitBreaker CircuitBreaker; | |
protected CircuitBreakerState(CircuitBreaker circuitBreaker) | |
{ | |
CircuitBreaker = circuitBreaker; | |
} | |
public virtual void ProtectedCodeIsAboutToBeCalled() | |
{ | |
} | |
public virtual void ProtectedCodeHasBeenCalled() | |
{ | |
} | |
public virtual void ActUponException(Exception e) | |
{ | |
} | |
} | |
#endregion | |
#region Nested type: ClosedState | |
private class ClosedState : CircuitBreakerState | |
{ | |
public ClosedState(CircuitBreaker circuitBreaker) | |
: base(circuitBreaker) | |
{ | |
circuitBreaker.ResetFailureCount(); | |
} | |
public override void ActUponException(Exception e) | |
{ | |
if (CircuitBreaker.ThresholdReached()) CircuitBreaker.MoveToOpenState(); | |
} | |
} | |
#endregion | |
#region Nested type: HalfOpenState | |
private class HalfOpenState : CircuitBreakerState | |
{ | |
public HalfOpenState(CircuitBreaker circuitBreaker) | |
: base(circuitBreaker) | |
{ | |
} | |
public override void ActUponException(Exception e) | |
{ | |
CircuitBreaker.MoveToOpenState(); | |
} | |
public override void ProtectedCodeHasBeenCalled() | |
{ | |
CircuitBreaker.MoveToClosedState(); | |
} | |
} | |
#endregion | |
#region Nested type: OpenState | |
private class OpenState : CircuitBreakerState | |
{ | |
private readonly Timer _timer; | |
public OpenState(CircuitBreaker circuitBreaker) | |
: base(circuitBreaker) | |
{ | |
_timer = new Timer(circuitBreaker._timeout.TotalMilliseconds); | |
_timer.Elapsed += TimeoutHasBeenReached; | |
_timer.AutoReset = false; | |
_timer.Start(); | |
} | |
private void TimeoutHasBeenReached(object sender, ElapsedEventArgs e) | |
{ | |
CircuitBreaker.MoveToHalfOpenState(); | |
} | |
public override void ProtectedCodeIsAboutToBeCalled() | |
{ | |
throw new OpenCircuitException(); | |
} | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment