我正在寻找在连接成功之前无法控制地远程调用服务的方法。我也不想简单地设置一个计时器,该计时器每n秒/分钟执行一次操作,直到成功为止。经过大量研究,看来断路器模式非常合适。

我发现一个implementation使用城堡温莎城堡拦截器,看起来很棒。唯一的问题是我不知道如何使用它。在有关该主题的几篇文章中,我唯一能找到的用法示例就是仅使用断路器一次调用一个 Action ,这似乎没有什么用。由此看来,我需要在while(true)循环中使用断路器简单地运行我的 Action 。

我如何使用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();
    }
}

基于此,我认为我现在已经理解了这个概念以及如何应用它。

最佳答案

如果您有很多线程访问同一资源,这是一个有趣的想法。这种工作方式是通过汇总所有线程的尝试计数。您不必担心编写循环来尝试在实际失败之前尝试访问数据库5次,而让断路器跟踪所有尝试访问资源的尝试。

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

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

假设您的错误处理正确无误,并且所有循环都可以运行5次,并且对资源执行ping操作总共50次。

断路器尝试减少尝试到达资源的总次数。每个线程或请求尝试将增加一个错误计数器。一旦达到错误限制,断路器将不会尝试连接到它的资源以在任何线程上进行更多调用,直到超时时间过去为止。在资源准备好之前轮询它仍然具有相同的效果,但是可以减少总负载。
static volatile int errorCount = 0;

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

使用此拦截器实现,拦截器将被注册为单例。因此,对于任何方法的任何调用,资源类的所有实例将首先通过断路器重定向代码。上课的interceptor is just a proxy。它基本上会覆盖您的方法,并在调用您的方法之前先调用拦截器方法。

如果您没有任何电路理论知识,则“开/关”位可能会造成混淆。
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 */
        }
    }

09-03 19:58