1.前言
在上一篇云计算设计模式之基于消息队列的负载均衡模式中,我们讨论了消息队列对于高并发应用的巨大作用.这一篇,我们讨论下重试模式.
2.概念
准确来说,重试模式只是一个简单的技巧而已.在连接网络、服务的过程中很有可能出现瞬时错误,那么在连接的时候,设计一种内部重试机制就很有必要了.在一定的时间内重试成功,认为连接是成功的,一定时间内重试失败,才认为失败.
应用应该在连接网络、服务的方法中封装一种重试机制,并且记录连接失败的信息在log中.可以针对不同的服务指定不同的策略.
3.Example
下面的代码演示了重试机制:
private int retryCount = 3;
...
public async Task OperationWithBasicRetryAsync()
{
int currentRetry = 0;
for (; ;)
{
try
{
// Calling external service.
await TransientOperationAsync();
// Return or break.
break;
}
catch (Exception ex)
{
Trace.TraceError("Operation Exception");
currentRetry++;
// Check if the exception thrown was a transient exception
// based on the logic in the error detection strategy.
// Determine whether to retry the operation, as well as how
// long to wait, based on the retry strategy.
if (currentRetry > this.retryCount || !IsTransient(ex))
{
// If this is not a transient error
// or we should not retry re-throw the exception.
throw;
}
}
// Wait to retry the operation.
// Consider calculating an exponential delay here and
// using a strategy best suited for the operation and fault.
Await.Task.Delay();
}
}
// Async method that wraps a call to a remote service (details not shown).
private async Task TransientOperationAsync()
{
...
}
我们讲到在一定时间阀值内连接成功,我们也需要记录相关异常信息.
private bool IsTransient(Exception ex)
{
// Determine if the exception is transient.
// In some cases this may be as simple as checking the exception type, in other
// cases it may be necessary to inspect other properties of the exception.
if (ex is OperationTransientException)
return true;
var webException = ex as WebException;
if (webException != null)
{
// If the web exception contains one of the following status values
// it may be transient.
return new[] {WebExceptionStatus.ConnectionClosed,
WebExceptionStatus.Timeout,
WebExceptionStatus.RequestCanceled }.
Contains(webException.Status);
}
// Additional exception checking logic goes here.
return false;
}
4.相关阅读
The following pattern may also be relevant when implementing this pattern:
- Circuit Breaker Pattern. The Retry pattern is ideally suited to handling transient faults. If a failure is expected to be more long lasting, it may be more appropriate to implement the Circuit Breaker Pattern. The Retry pattern can also be used in conjunction with a circuit breaker to provide a comprehensive approach to handling faults.
- The Transient Fault Handling Application Block on MSDN.
- The article Connection Resiliency / Retry Logic (EF6 onwards) on MSDN.