网络中断后,Polly Circuit Breaker /重试可自动重新启动查询

时间:2018-11-09 20:42:12

标签: circuit-breaker polly retrypolicy

我正在.NET Framework 4.5.2中通过Polly实现断路器和重试模式。

我想看看我的理解是否正确。

问题1:如果发生网络中断,并且断路器达到了AllowedBeforeBreaking编号,进入断开状态并等待BreakingOfBreak周期的异常,则电路将断开以接受新请求,但已发送的请求将抛出例外?

问题2:如果期望的行为是针对那些具有异常的重试请求,而不是断路器抛出异常,那么除了断路器策略之外,还需要实施重试策略。我的理解是,问题1的行为会发生,然后尝试重试。

A。如果网络中断或服务关闭,并且期望的行为是在网络恢复或服务再次启动后立即重试请求,则需要执行RetryForever。有更好的方法吗?有效地会有很多阻碍,对吗?

就代码而言,我的策略当前定义为:

    const int maxRetryAttempts = 3;

    const int exceptionsAllowedBeforeBreaking = 2;
    const int pauseBetweenFailures = 2;
    readonly Policy retryPolicy = Policy
        .Handle<Exception>()
        .RetryAsync(maxRetryAttempts, (exception, retryCount) => System.Diagnostics.Debug.WriteLine($"Retry {retryCount}"));

    readonly Policy circuitBreakerPolicy = Policy
        .Handle<Exception>()
        .CircuitBreakerAsync(exceptionsAllowedBeforeBreaking: exceptionsAllowedBeforeBreaking,
                durationOfBreak: TimeSpan.FromSeconds(pauseBetweenFailures),
                onBreak: (e, span) => System.Diagnostics.Debug.WriteLine("Breaking circuit for " + span.TotalMilliseconds + "ms due to " + e.Message),
                onReset: () => System.Diagnostics.Debug.WriteLine("Trial call succeeded: circuit closing again."),
                onHalfOpen: () => System.Diagnostics.Debug.WriteLine("Circuit break time elapsed.  Circuit now half open: permitting a trial call."));

我的呼叫代码如下:

var response = await retryPolicy.WrapAsync(circuitBreakerPolicy).ExecuteAsync(() => this.client.SendAsync<TData, JObject>(message, cancel, jsonSerializer));

我观察到,如果我断开网络的连接超过了在断路器上运行所有重试所需的时间,则CancellationToken设置为取消,并且所有请求都将在此时失败。如果在此之前恢复了网络,则将重试请求。

2 个答案:

答案 0 :(得分:0)

  

问题1:如果发生网络中断,并且断路器已达到AllowedBeforeBreaking编号例外,进入断开状态并等待BreakingOfBreak周期,则电路将断开以接受新请求...

durationOfBreak经过之后,电路将转换为半开状态,在此期间a single trial call is permitted (in the current implementation)

  

...但是已发送的邮件将引发异常?

placed during the Open state will throw BrokenCircuitException的呼叫。

  

问题2:如果期望的行为是针对那些具有异常的重试请求,而不是断路器抛出异常,那么除了断路器策略之外,还需要实施重试策略。我的理解是,问题1的行为会发生,然后尝试重试。

正确。断路器仍会抛出该BrokenCircuitException(没有“代替”会阻止断路器这样做)。但是,如果包装重试策略处理该异常,则BrokenCircuitException将不会传播回调用代码。可运行的示例可以在Polly-Samplesthis dotnetfiddle中找到。

  

A。如果网络中断或服务关闭,并且期望的行为是在网络恢复或服务再次启动后立即重试请求,则需要执行RetryForever。有效地会有很多阻碍,对吗?

Polly策略仅控制在该执行路径上发生的事情,而不知道是否存在类似的并行执行。因此,是的,如果有一个RetryForever,并且您希望在失去连接的情况下在该RetryForever中有大量呼叫循环,则存在保持模式中的许多操作会导致内存/资源膨胀。要知道这是否对您的应用程序/体系结构而言是一个重大问题,您需要在具有代表性的环境中进行试用。

  

是否有更好的方法?

您可以限制重试次数,并将失败的发送捕获到某种队列中。恢复连接后,您可以重新发送故障队列中的项目。

答案 1 :(得分:0)

我不是RetryForever政策的忠实拥护者。如果遇到通过INSERT语句将80,000条记录插入表的情况,该怎么办。突然发生网络问题。您将立即拥有80k异步进程来占用您的系统资源。我强烈建议使用Retry,BulkHead和Circuitbreaker进行策略包装。我编写了一个自定义SQLExtension类,该类具有secondaryfallback connectionstring和fallback命令,以便在断路器用尽时将关键事务写入某些辅助sql服务器。需要注意的其他事项。您可以跟踪特定的SQL异常错误,主要是重复项。假设您的sql命令不是简单的Insert命令,而是复杂的存储过程。一旦释放,断路器将简单地重新运行存储过程,并在具有主键的表上产生重复发现的消息。因此,您可能要忽略重复的消息。