我如何使用断路器?

我正在寻找在我的控制之外远程调用服务的方法,直到连接成功为止。 我也不想简单地设置一个定时器,每隔n秒/分钟执行一次动作,直到成功为止。 经过一系列研究后,似乎断路器模式非常适合。

我找到了一个使用Castle Windsor拦截器的实现,看起来很棒。 唯一的问题是我不知道如何使用它。 从我发现的关于该主题的几篇文章中,我能够找到的唯一用法示例是简单地使用断路器仅调用一次动作,这似乎不太有用。 从那看起来我需要在一段while(true)循环中使用断路器简单地运行我的动作。

我如何使用Windsor拦截器执行一个动作来调用外部服务,直到它成功而不会关闭我们的服务器?

有人可以填写缺失的部分吗?

这是我能想到的

 while(true) { try { service.Subscribe(); break; } catch (Exception e) { Console.WriteLine("Gotcha!"); Thread.Sleep(TimeSpan.FromSeconds(10)); } } Console.WriteLine("Success!"); public interface IService { void Subscribe(); } public class Service : IService { private readonly Random _random = new Random(); public void Subscribe() { var a = _random.Next(0, 10) % 2421; if(_random.Next(0, 10) % 2 != 0) throw new AbandonedMutexException(); } } 

基于此,我想我现在理解这个概念以及如何应用它。

如果你有很multithreading命中相同的资源,这是一个有趣的想法。 这种方式的工作方式是汇集所有线程的尝试计数。 而不是担心编写一个循环来尝试在实际失败之前尝试击中数据库5次,而是让断路器跟踪所有击中资源的尝试。

在一个例子中,你说5个线程运行这样的循环(伪代码):

 int errorCount = 0; while(errorCount < 10) // 10 tries { if(tryConnect() == false) errorCount++; else break; } 

假设你的error handling是正确的,那么这个循环可以运行5次,并且总共ping资源50次。

断路器试图减少它尝试到达资源的总次数。 每个线程或请求尝试都将增加一个错误计数器。 一旦达到错误限制,断路器将不会尝试连接到它的资源,以便在超时之前对任何线程进行更多调用。 轮询资源直到它准备就绪仍然是相同的效果,但是你减少了总负载。

 static volatile int errorCount = 0; while(errorCount < 10) { if(tryConnect() == false) errorCount++; else break; } 

通过这种拦截器实现,拦截器被注册为单例。 因此,对于对任何方法的任何调用,您的资源类的所有实例都将首先通过断路器重定向代码。 拦截器只是你class级的代理 。 它基本上覆盖了你的方法,并在调用你的方法之前先调用拦截器方法。

如果您没有任何电路理论知识,则打开/关闭位可能会令人困惑。 维基:

如果电路在其电源的正极和负极之间缺少完整的路径,则该电路是“开路”

理论上,当连接断开时,此电路为打开,当连接可用时,此电路为闭合。 您的示例的重要部分是:

 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 */ } } 

我创建了一个名为CircuitBreaker.Net的库,它封装了所有服务逻辑以安全地执行调用。 它易于使用,示例可能如下所示:

 // Initialize the circuit breaker var circuitBreaker = new CircuitBreaker( TaskScheduler.Default, maxFailures: 3, invocationTimeout: TimeSpan.FromMilliseconds(100), circuitResetTimeout: TimeSpan.FromMilliseconds(10000)); try { // perform a potentially fragile call through the circuit breaker circuitBreaker.Execute(externalService.Call); // or its async version // await circuitBreaker.ExecuteAsync(externalService.CallAsync); } catch (CircuitBreakerOpenException) { // the service is unavailable, failover here } catch (CircuitBreakerTimeoutException) { // handle timeouts } catch (Exception) { // handle other unexpected exceptions } 

它可以通过nuget包获得 。 你可以在github上找到这些资源 。