有时,我需要在放弃之前将一个操作重试几次。我的代码是:
int retries = 3;
while(true) {
try {
DoSomething();
break; // success!
} catch {
if(--retries == 0) throw;
else Thread.Sleep(1000);
}
}
我想在一个通用的重试函数中重写这个:
TryThreeTimes(DoSomething);
这在c#中可行吗?TryThreeTimes()方法的代码是什么?
用c#、Java或其他语言简单地完成:
internal class ShouldRetryHandler {
private static int RETRIES_MAX_NUMBER = 3;
private static int numberTryes;
public static bool shouldRetry() {
var statusRetry = false;
if (numberTryes< RETRIES_MAX_NUMBER) {
numberTryes++;
statusRetry = true;
//log msg -> 'retry number' + numberTryes
}
else {
statusRetry = false;
//log msg -> 'reached retry number limit'
}
return statusRetry;
}
}
并在你的代码中简单地使用它:
void simpleMethod(){
//some code
if(ShouldRetryHandler.shouldRetry()){
//do some repetitive work
}
//some code
}
或者你可以在递归方法中使用它:
void recursiveMethod(){
//some code
if(ShouldRetryHandler.shouldRetry()){
recursiveMethod();
}
//some code
}
您还可以考虑添加要重试的异常类型。例如,这是您想要重试的超时异常吗?数据库异常?
RetryForExcpetionType(DoSomething, typeof(TimeoutException), 5, 1000);
public static void RetryForExcpetionType(Action action, Type retryOnExceptionType, int numRetries, int retryTimeout)
{
if (action == null)
throw new ArgumentNullException("action");
if (retryOnExceptionType == null)
throw new ArgumentNullException("retryOnExceptionType");
while (true)
{
try
{
action();
return;
}
catch(Exception e)
{
if (--numRetries <= 0 || !retryOnExceptionType.IsAssignableFrom(e.GetType()))
throw;
if (retryTimeout > 0)
System.Threading.Thread.Sleep(retryTimeout);
}
}
}
您可能还注意到,所有其他示例在测试retries == 0时都存在类似的问题,要么重试无穷大,要么在给定负值时无法引发异常。Sleep(-1000)在上面的catch块中也会失败。这取决于你期望人们有多“愚蠢”,但防御性编程永远不会伤害到你。
6年后更新:现在我认为下面的方法非常糟糕。为了创建重试逻辑,我们应该考虑使用Polly这样的库。
重试方法的异步实现:
public static async Task<T> DoAsync<T>(Func<dynamic> action, TimeSpan retryInterval, int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
return await action().ConfigureAwait(false);
}
catch (Exception ex)
{
exceptions.Add(ex);
}
await Task.Delay(retryInterval).ConfigureAwait(false);
}
throw new AggregateException(exceptions);
}
重点:我使用。configureawait (false);和Func<dynamic>代替Func<T>