Skip to content

Instantly share code, notes, and snippets.

@davybrion
Created September 6, 2012 13:07
Show Gist options
  • Save davybrion/3656057 to your computer and use it in GitHub Desktop.
Save davybrion/3656057 to your computer and use it in GitHub Desktop.
code snippets for "The Circuit Breaker" post
public abstract class CircuitBreakerState
{
protected readonly CircuitBreaker circuitBreaker;
protected CircuitBreakerState(CircuitBreaker circuitBreaker)
{
this.circuitBreaker = circuitBreaker;
}
public virtual void ProtectedCodeIsAboutToBeCalled() { }
public virtual void ProtectedCodeHasBeenCalled() { }
public virtual void ActUponException(Exception e) { circuitBreaker.IncreaseFailureCount(); }
}
public class ClosedState : CircuitBreakerState
{
public ClosedState(CircuitBreaker circuitBreaker) : base(circuitBreaker)
{
circuitBreaker.ResetFailureCount();
}
public override void ActUponException(Exception e)
{
base.ActUponException(e);
if (circuitBreaker.ThresholdReached()) circuitBreaker.MoveToOpenState();
}
}
public 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()
{
base.ProtectedCodeIsAboutToBeCalled();
throw new OpenCircuitException();
}
}
public class HalfOpenState : CircuitBreakerState
{
public HalfOpenState(CircuitBreaker circuitBreaker) : base(circuitBreaker) {}
public override void ActUponException(Exception e)
{
base.ActUponException(e);
circuitBreaker.MoveToOpenState();
}
public override void ProtectedCodeHasBeenCalled()
{
base.ProtectedCodeHasBeenCalled();
circuitBreaker.MoveToClosedState();
}
}
public class CircuitBreaker
{
private readonly object monitor = new object();
private CircuitBreakerState state;
public CircuitBreaker(int threshold, TimeSpan timeout)
{
if (threshold < 1)
{
throw new ArgumentOutOfRangeException("threshold", "Threshold should be greater than 0");
}
if (timeout.TotalMilliseconds < 1)
{
throw new ArgumentOutOfRangeException("timeout", "Timeout should be greater than 0");
}
Threshold = threshold;
Timeout = timeout;
MoveToClosedState();
}
public int Failures { get; private set; }
public int Threshold { get; private set; }
public TimeSpan Timeout { get; private set; }
public bool IsClosed
{
get { return state is ClosedState; }
}
public bool IsOpen
{
get { return state is OpenState; }
}
public bool IsHalfOpen
{
get { return state is HalfOpenState; }
}
internal void MoveToClosedState()
{
state = new ClosedState(this);
}
internal void MoveToOpenState()
{
state = new OpenState(this);
}
internal void MoveToHalfOpenState()
{
state = new HalfOpenState(this);
}
internal void IncreaseFailureCount()
{
Failures++;
}
internal void ResetFailureCount()
{
Failures = 0;
}
public bool ThresholdReached()
{
return Failures >= Threshold;
}
public void AttemptCall(Action protectedCode)
{
using (TimedLock.Lock(monitor))
{
state.ProtectedCodeIsAboutToBeCalled();
}
try
{
protectedCode();
}
catch (Exception e)
{
using (TimedLock.Lock(monitor))
{
state.ActUponException(e);
}
throw;
}
using (TimedLock.Lock(monitor))
{
state.ProtectedCodeHasBeenCalled();
}
}
public void Close()
{
using (TimedLock.Lock(monitor))
{
MoveToClosedState();
}
}
public void Open()
{
using (TimedLock.Lock(monitor))
{
MoveToOpenState();
}
}
}
public void ProcessOrder(OrderInfo orderInfo)
{
var proxy = new OrderProcessorServiceProxy();
_orderProcessoryCircuitBreaker.AttemptCall(() => proxy.ProcessOrder(orderInfo));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment