Polly简单使用

发布时间 2023-06-17 02:11:56作者: 广州大雄

简介

Polly 是一个针对 .NET 应用程序的库,提供了一系列经过优化的故障处理策略,帮助开发人员实现重试、断路器、超时和熔断机制等。通过 Polly 库,开发人员可以更容易地编写鲁棒性更强、更可靠的应用程序。

Retry 策略

当出现异常或错误时,自动重试指定次数。

static void Main()
{
	try
	{
		//捕获DivideByZeroException异常会重试三次
		var retryTwoTimesPolicy =
			 Policy
				//处理多个异常类型通过OR即可
				 .Handle<DivideByZeroException>().Or<ArgumentException>()
				 .Retry(3, (ex, count) =>
				 {
					 Console.WriteLine("执行失败! 重试次数 {0}", count);
					 Console.WriteLine("异常来自 {0}", ex.GetType().Name);
				 });
		retryTwoTimesPolicy.Execute(() =>
		{
			var a = 0;
			return 1 / a;
		});
	}
	catch (Exception ex)
	{
		//第四次异常不做处理,抛出异常
		Console.WriteLine($"catch {ex.GetType().Name}");
	}
	finally
	{
		Console.WriteLine($"finally");
	}
}

image

static void Main()
{
	try
	{
		//捕获DivideByZeroException异常会重试三次
		var retryTwoTimesPolicy =
			 Policy
				 //处理多个异常类型通过OR即可
				 .Handle<DivideByZeroException>().Or<ArgumentException>()
				 //添加重新间隔
				 .WaitAndRetry(new[]
				 {
						TimeSpan.FromSeconds(1),
						TimeSpan.FromSeconds(3),
						TimeSpan.FromSeconds(5),
				 }, (ex, TimeSpan) =>
				 {
					 Console.WriteLine($"执行失败! 执行间隔 {TimeSpan} {DateTime.Now}");
					 Console.WriteLine($"异常来自 {ex.GetType().Name}");
				 });

				retryTwoTimesPolicy.Execute(() =>
				{
					var a = 0;
					return 1 / a;
				});
	}
	catch (Exception ex)
	{
		Console.WriteLine($"catch {ex.GetType().Name}");
	}
	finally
	{
		Console.WriteLine($"finally");
	}
}

image

Timeout 策略

在规定时间内未获取到响应时,自动取消请求并抛出超时异常。

static async Task Main()
{

	// 创建超时策略,等待最多 1 秒钟
	// 如果在等待时间内未完成操作,则会抛出 TimeoutRejectedException 异常。
	var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(1), TimeoutStrategy.Pessimistic);

	try
	{
		// 在超时策略中执行操作
		await timeoutPolicy.ExecuteAsync(async (ct) =>
		{
			using (HttpClient httpClient = new HttpClient())
			{
				var response = await httpClient.GetAsync("https://www.example.com", ct);

				// 处理响应结果
				response.EnsureSuccessStatusCode();
				var content = await response.Content.ReadAsStringAsync(ct);
				Console.WriteLine(content);
			}
		}, CancellationToken.None);
		/*
		 * 最后,我们使用 ExecuteAsync 方法,在组合策略中执行异步操作,并在 CancellationToken 参数中传递 CancellationToken.None 来允许取消操作。
		 * 如果在指定的等待时间内没有得到响应,则会抛出 TimeoutRejectedException 异常。如果操作失败,则会捕获异常并输出相应的信息。
		 */

	}
	catch (TimeoutRejectedException)
	{
		Console.WriteLine("The operation timed out.");
	}
	catch (Exception ex)
	{
		Console.WriteLine($"Exception caught: {ex.GetType().Name}");
	}
}

image

Circuit Breaker 策略

当某个远程服务发生异常或错误时,自动跳闸断路,避免进一步请求对该服务造成负载压力和损害。

static async Task Main()
{
	//连续失败 5 次,那么断路器会被打开,并保持 5 秒钟的打开状态时间,防止继续执行相同的操作
	var circuitBreakerPolicy = Policy
		.Handle<Exception>()
		.CircuitBreaker(5, TimeSpan.FromSeconds(5));

	// 对多个操作使用相同的断路器策略
	for (int i = 0; i < 20; i++)
	{
		try
		{
			await Task.Delay(TimeSpan.FromSeconds(1));
			// 尝试执行某些可能会抛出异常的操作
			circuitBreakerPolicy.Execute(() =>
			{
				// TODO: 执行某些操作,可能会抛出异常
				throw new Exception($"异常");
			});
		}
		catch (Exception ex)
		{
			// 断路器开启,操作被拒绝
			Console.WriteLine($"time:{DateTime.Now} Num:{i} failed: {ex.Message}");
		}
	}
}

image

Microsoft.Extensions.Http.Polly

是基于 Polly 的一个 ASP.NET Core HttpClient 工厂的扩展库,它能够为应用程序提供简单易用的、可扩展的 HTTP 客户端工厂,并且可以很容易地实现重试、熔断、超时等策略。

var retryPolicy = HttpPolicyExtensions
   .HandleTransientHttpError()
   .Or<TimeoutRejectedException>() // thrown by Polly's TimeoutPolicy if the inner execution times out
   .RetryAsync(3);

var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
//更方便的使用polliy
services.AddHttpClient("example.com", c => c.BaseAddress = new Uri("http://example.com"))
	  .AddPolicyHandler(retryPolicy)
	  .AddPolicyHandler(timeoutPolicy);

参考

https://github.com/App-vNext/Polly
https://github.com/App-vNext/Polly.Extensions.Http/blob/master/README.md