.NET微服务从0到1:服务容错(Polly)
Polly是 .NET 平台下的一个弹性和瞬态故障处理库,它允许开发人员以流畅和线程安全的方式表达策略,如重试、熔断器、超时、舱壁隔离和回退等
重试
进行一次重试
Retry()
无参数表示重试一次
private static async Task RetryOnce()
{
var policy = Policy.Handle<CustomException>()
.Retry(3);
await policy.Execute(() => FooFunction());
}
执行结果
进行多次重试
Retry(N)
表示执行N此重试
var policy = Policy.Handle<CustomException>()
.Retry(3);
await policy.Execute(() => FooFunction());
执行结果
一直重试直到成功
使用
RetryForever()
不断重试
private static async Task RetryForeverUntilSuccess()
{
var policy = Policy.Handle<CustomException>()
.RetryForever();
await policy.Execute(() => FooFunction());
}
执行结果
等待指定时间后重试
使用
WaitAndRetry()
和WaitAndRetryAsync()
在指定等待时间后重试
private static async Task RetryAfterWait()
{
var policy = Policy.Handle<CustomException>()
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(4)
});
await policy.ExecuteAsync(() => FooFunction());
}
等待指定时间后不断重试直到成功
使用
WaitAndRetryForever()
或WaitAndRetryForeverAsync()
在等待指定实际后不断重试,知道成功
private static async Task RetryForeverUntilSuccessAfterWait()
{
var policy = Policy.Handle<CustomException>()
.WaitAndRetryForeverAsync(retryAttempt =>
TimeSpan.FromSeconds(1));
await policy.ExecuteAsync(() => FooFunction());
}
每一次重试前的自定义逻辑处理
每一次重试前,我们可以自定义一些逻辑处理,比如日志记录等。
private static async Task RetryManyWithCustomLogic()
{
var policy = Policy.Handle<CustomException>()
.Retry(3, onRetry: (exception, retryCount) =>
{
Console.WriteLine($"{nameof(RetryManyWithCustomLogic)},第{retryCount}重试:{exception.Message}");
});
await policy.Execute(() => FooFunction());
}
执行结果
熔断
使用
CircuitBreaker
对调用进行熔断控制
public static async Task CircuitBreaker()
{
// 熔断策略:如果连续3次出发了CustomException异常,将在2秒内终止所有请求
var policy = Policy.Handle<CustomException>()
.CircuitBreaker(3, TimeSpan.FromSeconds(2));
for (int i = 0; i < 10; i++) // 模拟10次调用
{
try
{
await policy.Execute(() => FooFunction());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
await Task.Delay(1000);
}
}
}
执行结果
回退(Fallback)
Fallback
可以让我们程序咋发生一些故障时,提供备份操作(应急计划)
public static void Fallback()
{
var policy = Policy.Handle<CustomException>()
.Fallback(async () => FunctionFallback());
policy.Execute(() => Function());
}
上文中的一些省略的代码
- 定义一个异常/故障
class CustomException : Exception
{
public CustomException(string message) : base(message){}
}
- 要执行的函数
static int ctr = 0;
static Task FooFunction()
{
ctr++;
if (ctr >= 11) // 假设重试10次执行成功
{
return default;
}
Console.WriteLine($"{DateTime.Now:HH:mm:ss fff} {nameof(FooFunction)}:第{ctr}次执行");
throw new CustomException($"{nameof(FooFunction)}发生异常");
}
static void Function()
{
try
{
throw new CustomException($"{nameof(Function)}发生异常");
}
catch (Exception ex)
{
Console.WriteLine($"执行{nameof(Function)}发生异常:{ex.Message}");
throw;
}
}
static void FunctionFallback()
{
Console.WriteLine($"执行{nameof(FunctionFallback)}");
}
- 主函数
static async Task Main(string[] args)
{
Console.WriteLine("开始执行");
try
{
await RetryOnce();
}
catch (Exception ex)
{
Console.WriteLine($"{nameof(Main)}发生异常:{ex.Message}");
}
finally
{
Console.WriteLine("执行结束");
}
}