What are some implementations of Exception filtering in the Circuit Breaker pattern?
-
19-09-2019 - |
Question
The Circuit Breaker pattern, from the book Release It!, protects a remote service from requests while it is failing (or recovering) and helps the client manage repeated remote service failure. I like Davy Brion’s stateful circuit breaker and Ayende’s lazy timeout fix is very clean.
However, I have not seen a lot of implementations of filtering which exceptions will cause an increase in the failure count of a circuit breaker.
Don't worry about showing locking, unless your implementation is particularly dependent on clever locking. FYI, Phil Haack appears to have the latest version of TimedLock, used in Davy Brion's articles.
Solution
Filter by Predicate
A predicate can provide extended criteria and filtering logic.
public void AttemptCall(Action action, Predicate<Exception> match)
{
try
{
action();
}
catch(Exception e)
{
if(match(e))
state.ActUponException(e);
throw;
}
}
For example, you may want to increase the circuit breaker only on a WebException
caused by a timeout.
circuitBreaker.AttemptCall(() => service.DoWork(), e =>
{
WebException local = e as WebException;
if(local == null)
return false;
return local.Status == WebExceptionStatus.Timeout;
});
OTHER TIPS
Filter which Types will increase the count
Your first thought may be to construct a generic method call with a generic try... catch
block. However, the below will not work due to a .NET bug, please see these questions for more information.
public void AttemptCall<TException>(Action action)
where TException : Exception
{
try
{
action();
}
catch(TException e)
{
state.ActUponExcpetion(e);
throw;
}
}
You need to catch all exceptions and investigate the type.
public void AttemptCall<TException>(Action action)
where TException : Exception
{
try
{
action();
}
catch(TException e)
{
if(e is TException)
state.ActUponExcpetion(e);
throw;
}
}
Filter which Types will not increase the count
private readonly List<Exception> ignored = new List<Exception>();
public void Ignore<TException>()
where TException : Exception
{
Type type = typeof(TException);
if(ignored.Contains(type))
return;
ignored.Add(type);
}
public void AttemptCall(Action action)
{
try
{
action();
}
catch(Exception e)
{
if(!ignore.Contains(e.GetType()))
state.ActUponException(e);
throw;
}
}