Это интересная идея, если у вас много потоков, попадающих на один и тот же ресурс.Это работает путем объединения количества попыток из всех потоков.Вместо того, чтобы беспокоиться о том, чтобы написать цикл, чтобы попытаться выполнить попытку обращения к базе данных 5 раз, прежде чем произойдет сбой, у вас есть автоматический выключатель, который отслеживает все попытки попасть в ресурс.
В одном примере, скажем, работает 5 потоковцикл, подобный следующему (псевдокод):
int errorCount = 0;
while(errorCount < 10) // 10 tries
{
if(tryConnect() == false)
errorCount++;
else
break;
}
При условии правильной обработки ошибок и всего, этот цикл может быть выполнен 5 раз, а ресурс пропинговать всего 50 раз.
Автоматический выключатель пытается уменьшить общее количество попыток достичь ресурса.Каждый поток или попытка запроса будет увеличивать счетчик ошибок.Как только предел ошибки достигнут, автоматический выключатель не будет пытаться подключиться к его ресурсу для каких-либо дополнительных вызовов в любых потоках, пока не истечет время ожидания.Это все тот же эффект опроса ресурса, пока он не будет готов, но вы уменьшаете общую нагрузку.
static volatile int errorCount = 0;
while(errorCount < 10)
{
if(tryConnect() == false)
errorCount++;
else
break;
}
В этой реализации перехватчика перехватчик регистрируется как одиночный.Таким образом, все экземпляры вашего класса ресурсов будут перенаправлять код сначала через автоматический выключатель для любого вызова любого метода.Перехватчик является просто прокси для вашего класса.Он в основном переопределяет ваши методы и вызывает метод перехватчика, прежде чем вызывать ваш метод.
Бит Open / Closed может сбивать с толку, если у вас нет знаний по теории цепей. wiki:
Электрическая цепь - это «разомкнутая цепь», если ей не хватает полного пути между положительными и отрицательными клеммами источника питания
Теоретически эта цепь разомкнута, когда соединение разорвано, и замкнута, когда соединение доступно.Важная часть вашего примера такова:
public void Intercept(IInvocation invocation)
{
using (TimedLock.Lock(monitor))
{
state.ProtectedCodeIsAboutToBeCalled(); /* only throws an exception when state is Open, otherwise, it doesn't do anything. */
}
try
{
invocation.Proceed(); /* tells the interceptor to call the 'actual' method for the class that's being proxied.*/
}
catch (Exception e)
{
using (TimedLock.Lock(monitor))
{
failures++; /* increments the shared error count */
state.ActUponException(e); /* only implemented in the ClosedState class, so it changes the state to Open if the error count is at it's threshold. */
}
throw;
}
using (TimedLock.Lock(monitor))
{
state.ProtectedCodeHasBeenCalled(); /* only implemented in HalfOpen, if it succeeds the "switch" is thrown in the closed position */
}
}