Skip to content

Instantly share code, notes, and snippets.

@Vengarioth
Created October 7, 2015 15:29
Show Gist options
  • Save Vengarioth/6a382ae95c79d8d0aae9 to your computer and use it in GitHub Desktop.
Save Vengarioth/6a382ae95c79d8d0aae9 to your computer and use it in GitHub Desktop.
Lightweight, locking implementation of the Circuit Breaker pattern.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Integrations
{
/// <summary>
/// Circuit Breaker stability pattern.
///
/// The circuit breaker will reduce stress on external systems upon their failure
/// by limiting the calls made to it once a threshold on errors is reached
/// </summary>
public class CircuitBreaker
{
private enum CircuitBreakerState
{
//Closed means operations are carried out
Closed,
//Open means operations will fail automatically
Open,
//During HalfOpen, one operation is allowed, if it succeds the CircuitBreaker goes back to Closed
HalfOpen
}
private readonly string _name;
private readonly int _threshold;
private readonly TimeSpan _timeout;
private readonly object _lock;
private DateTime _timeoutEnd;
private int _failures;
private CircuitBreakerState _state;
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name of the protected system</param>
/// <param name="threshold">Threshold at which the Circuit Breaker blocks operations to the protected system</param>
/// <param name="timeout">Timeout after which the Circuit Breaker will retry to operate with the protected system</param>
public CircuitBreaker(string name, int threshold, TimeSpan timeout)
{
_name = name;
_threshold = threshold;
_timeout = timeout;
_lock = new object();
}
/// <summary>
/// Attempt an operation on the protected system.
/// Exceptions thrown by the given action will be used
/// to measure the protected systems health
/// </summary>
/// <param name="protectedAction">The action on the protected System, monitored by the Circuit Breaker</param>
public void Attempt(Action protectedAction)
{
switch (_state)
{
case CircuitBreakerState.Open:
lock (_lock)
{
if (DateTime.Now > _timeoutEnd)
{
_state = CircuitBreakerState.HalfOpen;
}
else
{
throw new IntegrationPointUnavailableException(_name);
}
}
break;
case CircuitBreakerState.HalfOpen:
throw new IntegrationPointUnavailableException(_name);
}
try
{
protectedAction();
}
catch (Exception e)
{
HandleException(e);
throw new IntegrationPointUnavailableException(_name, e);
}
switch (_state)
{
case CircuitBreakerState.Closed:
_failures = 0;
break;
case CircuitBreakerState.HalfOpen:
_state = CircuitBreakerState.Closed;
_failures = 0;
break;
}
}
private void HandleException(Exception e)
{
switch (_state)
{
case CircuitBreakerState.Closed:
if (++_failures > _threshold)
{
lock (_lock)
{
_state = CircuitBreakerState.Open;
_timeoutEnd = DateTime.Now.Add(_timeout);
}
}
break;
case CircuitBreakerState.HalfOpen:
lock (_lock)
{
_state = CircuitBreakerState.Open;
_timeoutEnd = DateTime.Now.Add(_timeout);
}
break;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment