Polly 在 .NET Core 中的弹性策略应用
安装依赖
在项目中使用 Polly 前,需通过 NuGet 安装核心包:
<PackageReference Include="Polly" Version="7.2.3" />
超时控制:乐观与悲观模式
Polly 提供两种异步超时处理机制。悲观模式会在任务执行期间主动监控耗时,并在超时时抛出异常;而乐观模式依赖任务内部对 CancellationToken 的响应。
// 悲观超时:强制中断长时间运行的操作
var pessimisticPolicy = Policy.TimeoutAsync(
2,
TimeoutStrategy.Pessimistic,
(ctx, span, ct) =>
{
Console.WriteLine("操作已超时(悲观)");
return Task.CompletedTask;
});
await pessimisticPolicy.ExecuteAsync(async () =>
{
Console.WriteLine("开始执行耗时操作...");
await Task.Delay(10000); // 模拟长任务
});
// 乐观超时:需配合可取消操作使用
var optimisticPolicy = Policy.TimeoutAsync(
1,
TimeoutStrategy.Optimistic,
(ctx, span, task) =>
{
Console.WriteLine("任务因超时被取消(乐观)");
});
await optimisticPolicy.ExecuteAsync(async token =>
{
Console.WriteLine("启动可取消任务...");
await Task.Delay(5000, token);
});
重试机制:基于异常类型触发
可根据特定异常或状态码配置自动重试逻辑。以下示例演示当 HTTP 状态为 511 时进行最多三次重试。
var retryPolicy = Policy
.Handle<HttpRequestException>(ex =>
(int)ex.StatusCode == 511)
.RetryAsync(3, (outcome, attempt) =>
{
Console.WriteLine($"第 {attempt} 次重试,原因: {outcome.Exception.Message}");
});
await retryPolicy.ExecuteAsync(async () =>
{
Console.WriteLine("正在尝试请求...");
throw new HttpRequestException("网络认证需求", innerException: null, HttpStatusCode.NetworkAuthenticationRequired);
});
降级处理:保障系统可用性
当核心服务失败且重试无效后,可通过 fallback 返回默认值,避免整个调用链崩溃。
var fallbackPolicy = Policy<string>
.Handle<HttpRequestException>(ex => ex.StatusCode == HttpStatusCode.VariantAlsoNegotiates)
.Or<Exception>()
.FallbackAsync(
fallbackValue: "降级响应",
onFallbackAsync: token =>
{
Console.WriteLine("已进入降级逻辑");
return Task.CompletedTask;
});
var combinedPolicy = fallbackPolicy.WrapAsync(retryPolicy);
string result = await combinedPolicy.ExecuteAsync(async () =>
{
Console.WriteLine("执行主业务流程");
throw new Exception("未知错误");
return "正常响应";
});
if (result == "降级响应")
{
Console.WriteLine("当前返回来自降级方案");
}
熔断器:防止雪崩效应
熔断器有三种状态:关闭(正常)、打开(拒绝请求)、半开(试探恢复)。当连续失败达到阈值时触发熔断,暂停请求一段时间后再尝试恢复。
var circuitBreaker = Policy
.Handle<Exception>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 2,
durationOfBreak: TimeSpan.FromSeconds(5),
onBreak: (ex, ts) => Console.WriteLine("熔断器开启,停止请求"),
onReset: () => Console.WriteLine("熔断器关闭,恢复正常"),
onHalfOpen: () => Console.WriteLine("熔断器半开,试探请求"));
// 组合策略:先重试再熔断,最后降级兜底
var recoveryPipeline = Policy<string>
.Handle<HttpRequestException>()
.Or<BrokenCircuitException>()
.FallbackAsync("熔断降级", _ =>
{
Console.WriteLine("触发最终降级");
return Task.CompletedTask;
})
.WrapAsync(circuitBreaker.WrapAsync(retryPolicy));
string output;
do
{
output = await recoveryPipeline.ExecuteAsync(() =>
{
Console.WriteLine("发起业务调用");
throw new HttpRequestException("升级需求", null, HttpStatusCode.UpgradeRequired);
return Task.FromResult("成功结果");
});
} while (output == "熔断降级");
Console.WriteLine(output != "熔断降级" ? "请求已恢复" : "仍在降级中");