Skip to content

Instantly share code, notes, and snippets.

@dvhthomas
Created November 14, 2009 03:16
Show Gist options
  • Save dvhthomas/234358 to your computer and use it in GitHub Desktop.
Save dvhthomas/234358 to your computer and use it in GitHub Desktop.
Circuit Breaker implementation
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