重试,然后
HttpRequestException
每当我们谈论波利政策时,我们都可以区分两个不同的例外:
处理异常
-
它会触发给定策略的某种行为(在本例中为
HttpRequestException
).
-
如果策略无法成功,将再次抛出已处理的异常。
-
如果有其他策略,那么它可能会也可能不会处理该异常。
未处理的异常
-
它不会引起任何反应(例如
WebException
在我们的情况下)。
-
未处理的异常将流经策略。
-
如果有其他策略,那么它可能会也可能不会处理该异常。
“其中大约一半被波利抓获并重试。
然而,另一半最终进入了我的试捕区”
如果您的某些重试尝试失败,则可能会发生这种情况。换句话说,有些请求在6次尝试(5次重试和1次初始尝试)中都未能成功。
这可以通过以下两种工具之一轻松验证:
-
onRetry
+
context
-
Fallback
+
上下文
重试
+
上下文
这个
重试
在触发重试策略但在睡眠持续时间之前调用。代表收到
retryCount
。因此,为了能够连接/关联同一请求的单独日志条目,您需要使用某种关联id。最简单的方法是这样编码:
public static class ContextExtensions
{
private const string Key = "CorrelationId";
public static Context SetCorrelation(this Context context, Guid? id = null)
{
context[Key] = id ?? Guid.NewGuid();
return context;
}
public static Guid? GetCorrelation(this Context context)
{
if (!context.TryGetValue(Key, out var id))
return null;
if (id is Guid correlation)
return correlation;
return null;
}
}
下面是一个简化的例子:
待执行的方法
private async Task<string> Test()
{
await Task.Delay(1000);
throw new CustomException("");
}
政策
var retryPolicy = Policy<string>
.Handle<CustomException>()
.WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1),
(result, delay, retryCount, context) =>
{
var id = context.GetCorrelation();
Console.WriteLine($"{id} - #{retryCount} retry.");
});
用法
var context = new Context().SetCorrelation();
try
{
await retryPolicy.ExecuteAsync(async (ctx) => await Test(), context);
}
catch (CustomException)
{
Console.WriteLine($"{context.GetCorrelation()} - All retry has been failed.");
}
样本输出
3319cf18-5e31-40e0-8faf-1fba0517f80d - #1 retry.
3319cf18-5e31-40e0-8faf-1fba0517f80d - #2 retry.
3319cf18-5e31-40e0-8faf-1fba0517f80d - #3 retry.
3319cf18-5e31-40e0-8faf-1fba0517f80d - #4 retry.
3319cf18-5e31-40e0-8faf-1fba0517f80d - #5 retry.
3319cf18-5e31-40e0-8faf-1fba0517f80d - All retry has been failed.
退路
正如前面所说,每当策略无法成功时,它就会重新抛出已处理的异常。换句话说,如果策略失败,那么它会将问题升级到下一个级别(下一个外部策略)。
下面是一个简化的例子:
政策
var fallbackPolicy = Policy<string>
.Handle<CustomException>()
.FallbackAsync(async (result, ctx, ct) =>
{
await Task.FromException<CustomException>(result.Exception);
return result.Result; //it will never be executed << just to compile
},
(result, ctx) =>
{
Console.WriteLine($"{ctx.GetCorrelation()} - All retry has been failed.");
return Task.CompletedTask;
});
用法
var context = new Context().SetCorrelation();
try
{
var strategy = Policy.WrapAsync(fallbackPolicy, retryPolicy);
await strategy.ExecuteAsync(async (ctx) => await Test(), context);
}
catch (CustomException)
{
Console.WriteLine($"{context.GetCorrelation()} - All policies failed.");
}
样本输出
169a270e-acf7-45fd-8036-9bd1c034c5d6 - #1 retry.
169a270e-acf7-45fd-8036-9bd1c034c5d6 - #2 retry.
169a270e-acf7-45fd-8036-9bd1c034c5d6 - #3 retry.
169a270e-acf7-45fd-8036-9bd1c034c5d6 - #4 retry.
169a270e-acf7-45fd-8036-9bd1c034c5d6 - #5 retry.
169a270e-acf7-45fd-8036-9bd1c034c5d6 - All retry has been failed.
169a270e-acf7-45fd-8036-9bd1c034c5d6 - All policies failed.