我一直在考虑为简单的网络流实现基本的重试逻辑。这个想法是要处理三种类型的异常:
在草绘此草图时,我最终得到类似
var retriedObservable = observable.RetryWhen(x => x.SelectMany(ex =>
{
if (ex is ShouldCompleteException)
{
return Observable.Return<Exception>(null);
}
else if (ex is TransientNetworkException)
{
return Observable.Return(ex).Delay(TimeSpan.FromSeconds(1));
}
else
{
return Observable.Throw<Exception>(ex);
}
}).TakeUntil(ex => ex == null));
编辑:此示例已高度简化,仅显示了我在代码中看到的三种典型的错误处理模式。在现实世界中,当然还有很多其他东西。
该代码有效,但看起来过于复杂,并且我不确定特殊的“ null”值是否会在某个时候碰到我。
我还尝试了.Where()
和.Merge()
的组合,但是代码很快变得不可读。
是否有一种更简洁的方法(即更规范)来完成此基本错误处理?
答案 0 :(得分:1)
这会有所帮助:
var retriedObservable2 = observable.RetryWhen(exStream => Observable.Merge(
exStream.OfType<ShouldCompleteException>().Select(_ => (Exception)null),
exStream.NotOfType(typeof(ShouldCompleteException)).OfType<TransientNetworkException>().Delay(TimeSpan.FromSeconds(1)),
exStream.NotOfTypes(typeof(ShouldCompleteException), typeof(TransientNetworkException)).SelectMany(e => Observable.Throw<Exception>(e))
).TakeUntil(ex => ex == null));
使用以下扩展消息:
public static class X
{
public static IObservable<TSource> NotOfType<TSource>(this IObservable<TSource> source, Type t)
{
return source.Where(o => !t.IsInstanceOfType(o));
}
public static IObservable<TSource> NotOfTypes<TSource>(this IObservable<TSource> source, params Type[] ts)
{
return source.Where(o => ts.All(t => !t.IsInstanceOfType(o)));
}
}
答案 1 :(得分:0)
已经有很棒的库,例如Polly。但是,如果您想实现自己的实现,则可以执行以下操作。
您可以创建一个RetryPolicyHandler
类。同样,您可以使用接口对其进行抽象,并根据需要与任何IoC容器一起使用。通过以下实现添加类似RetryExecuteAsync
的方法。
public async Task RetryExecuteAsync(Func<Task> action)
{
int retryCount = default(int);
int maxNumberOfRetries = 5; // Or get from settings
while (true)
{
try
{
await action().ConfigureAwait(false);
break;
}
catch (ArgumentNullException)
{
// Something specific about this exception
if (++retryCount > maxNumberOfRetries)
throw;
}
catch (Exception)
{
if (++retryCount > maxNumberOfRetries)
throw;
}
}
}
然后您可以像这样使用它。
await this.retryPolicyHandler.RetryExecuteAsync(async () =>
{
// Whatever code you want to retry
}).ConfigureAwait(false);
如果需要,还可以创建其他特定方法。例如,ExecuteDeadlockRetryAsync
捕获SqlException
或ExecuteHttpCallRetryAsync
来处理HttpRequestException
并以另一种方式处理它们。