我正在.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设置为取消,并且所有请求都将在此时失败。如果在此之前恢复了网络,则将重试请求。
答案 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-Samples或this dotnetfiddle中找到。
A。如果网络中断或服务关闭,并且期望的行为是在网络恢复或服务再次启动后立即重试请求,则需要执行RetryForever。有效地会有很多阻碍,对吗?
Polly策略仅控制在该执行路径上发生的事情,而不知道是否存在类似的并行执行。因此,是的,如果有一个RetryForever
,并且您希望在失去连接的情况下在该RetryForever
中有大量呼叫循环,则存在保持模式中的许多操作会导致内存/资源膨胀。要知道这是否对您的应用程序/体系结构而言是一个重大问题,您需要在具有代表性的环境中进行试用。
是否有更好的方法?
您可以限制重试次数,并将失败的发送捕获到某种队列中。恢复连接后,您可以重新发送故障队列中的项目。
答案 1 :(得分:0)
我不是RetryForever政策的忠实拥护者。如果遇到通过INSERT语句将80,000条记录插入表的情况,该怎么办。突然发生网络问题。您将立即拥有80k异步进程来占用您的系统资源。我强烈建议使用Retry,BulkHead和Circuitbreaker进行策略包装。我编写了一个自定义SQLExtension类,该类具有secondaryfallback connectionstring和fallback命令,以便在断路器用尽时将关键事务写入某些辅助sql服务器。需要注意的其他事项。您可以跟踪特定的SQL异常错误,主要是重复项。假设您的sql命令不是简单的Insert命令,而是复杂的存储过程。一旦释放,断路器将简单地重新运行存储过程,并在具有主键的表上产生重复发现的消息。因此,您可能要忽略重复的消息。