有时,我需要在放弃之前将一个操作重试几次。我的代码是:
int retries = 3;
while(true) {
try {
DoSomething();
break; // success!
} catch {
if(--retries == 0) throw;
else Thread.Sleep(1000);
}
}
我想在一个通用的重试函数中重写这个:
TryThreeTimes(DoSomething);
这在c#中可行吗?TryThreeTimes()方法的代码是什么?
下面是一个async/await版本,它可以聚合异常并支持取消。
/// <seealso href="https://learn.microsoft.com/en-us/azure/architecture/patterns/retry"/>
protected static async Task<T> DoWithRetry<T>( Func<Task<T>> action, CancellationToken cancelToken, int maxRetries = 3 )
{
var exceptions = new List<Exception>();
for ( int retries = 0; !cancelToken.IsCancellationRequested; retries++ )
try {
return await action().ConfigureAwait( false );
} catch ( Exception ex ) {
exceptions.Add( ex );
if ( retries < maxRetries )
await Task.Delay( 500, cancelToken ).ConfigureAwait( false ); //ease up a bit
else
throw new AggregateException( "Retry limit reached", exceptions );
}
exceptions.Add( new OperationCanceledException( cancelToken ) );
throw new AggregateException( "Retry loop was canceled", exceptions );
}
如果将简单地重试同一个调用的通用catch语句用作通用异常处理机制,则可能是危险的。话虽如此,这里有一个基于lambda的重试包装器,您可以将其用于任何方法。为了获得更大的灵活性,我选择将重试次数和重试超时作为参数:
public static class Retry
{
public static void Do(
Action action,
TimeSpan retryInterval,
int maxAttemptCount = 3)
{
Do<object>(() =>
{
action();
return null;
}, retryInterval, maxAttemptCount);
}
public static T Do<T>(
Func<T> action,
TimeSpan retryInterval,
int maxAttemptCount = 3)
{
var exceptions = new List<Exception>();
for (int attempted = 0; attempted < maxAttemptCount; attempted++)
{
try
{
if (attempted > 0)
{
Thread.Sleep(retryInterval);
}
return action();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
你现在可以使用这个实用程序方法来执行重试逻辑:
Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1));
or:
Retry.Do(SomeFunctionThatCanFail, TimeSpan.FromSeconds(1));
or:
int result = Retry.Do(SomeFunctionWhichReturnsInt, TimeSpan.FromSeconds(1), 4);
或者你甚至可以做一个异步重载。
用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
}