官方对 Polly 的介绍是这样的:
Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.
翻译过来大概意思是:Polly 是一个 .NET 弹性和瞬态故障处理库,允许开发人员以 Fluent 和线程安全的方式来实现重试、断路、超时、隔离和回退策略。
这个描述有点抽象,我们一起来理解一下。
首先这里的说的瞬态故障包含了程序发生的异常和出现不符合开发者预期的结果。所谓瞬态故障,就是说故障不是必然会发生的,而是偶然可能会发生的,比如网络偶尔会突然出现不稳定或无法访问这种故障。至于弹性,就是指应对故障 Polly 的处理策略具有多样性和灵活性,它的各种策略可以灵活地定义和组合。
下面来演示一个例子,大家就更清楚了。
故障处理策略示例安惯例,创建一个空的 Console 项目,和安装 NuGet 包:
Install-Package Polly
Polly 的异常处理策略的基本用法可以分为三个步骤,步骤说明包含在下面代码中:
static void Main(string[] args) { Policy // 1. 指定要处理什么异常 .Handle<HttpRequestException>() // 或者指定需要处理什么样的错误返回 .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.BadGateway) // 2. 指定重试次数和重试策略 .Retry(3, (exception, retryCount, context) => { Console.WriteLine($"开始第 {retryCount} 次重试:"); }) // 3. 执行具体任务 .Execute(ExecuteMockRequest); Console.WriteLine("程序结束,按任意键退出。"); Console.ReadKey(); } static HttpResponseMessage ExecuteMockRequest() { // 模拟网络请求 Console.WriteLine("正在执行网络请求..."); Thread.Sleep(3000); // 模拟网络错误 return new HttpResponseMessage(HttpStatusCode.BadGateway); }
从例子中可以看到,Polly 的 API 支持流式(Fluent)调用,使用起来很方便。这个示例对错误处理的策略很简单,当发生请求异常或网络错误时,就重试 3 次。我们可以从下面的运行结果图看到这个策略的执行过程:
下面具体来看 Polly 支持的各种故障处理策略。
Polly 的七种策略Polly 可以实现重试、断路、超时、隔离、回退和缓存策略,下面给出这些策略的应用场景说明和基本使用方法。
重试(Retry)出现故障自动重试,这个是很常见的场景,上面也已经给出例子了,这里不再细述。
断路(Circuit-breaker)当系统遇到严重问题时,快速回馈失败比让用户/调用者等待要好,限制系统出错的体量,有助于系统恢复。比如,当我们去调一个第三方的 API,有很长一段时间 API 都没有响应,可能对方服务器瘫痪了。如果我们的系统还不停地重试,不仅会加重系统的负担,还会可能导致系统其它任务受影响。所以,当系统出错的次数超过了指定的阈值,就要中断当前线路,等待一段时间后再继续。
下面是一个基本的断路策略的使用方式:
Policy.Handle<SomeException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1));
这句代码设定的策略是,当系统出现两次某个异常时,就停下来,等待 1 分钟后再继续。这是基本的用法,你还可以在断路时定义中断的回调和重启的回调。
超时(Timeout)当系统超过一定时间的等待,我们就几乎可以判断不可能会有成功的结果。比如平时一个网络请求瞬间就完成了,如果有一次网络请求超过了 30 秒还没完成,我们就知道这次大概率是不会返回成功的结果了。因此,我们需要设置系统的超时时间,避免系统长时间做无谓的等待。
下面是超时策略的一个基本用法:
Policy.Timeout(30, onTimeout: (context, timespan, task) => { // do something });
这里设置了超时时间不能超过 30 秒,否则就认为是错误的结果,并执行回调。
隔离(Bulkhead Isolation)当系统的一处出现故障时,可能促发多个失败的调用,很容易耗尽主机的资源(如 CPU)。下游系统出现故障可能导致上游的故障的调用,甚至可能蔓延到导致系统崩溃。所以要将可控的操作限制在一个固定大小的资源池中,以隔离有潜在可能相互影响的操作。
下面是隔离策略的一个基本用法:
Policy.Bulkhead(12, context => { // do something });
这个策略是最多允许 12 个线程并发执行,如果执行被拒绝,则执行回调。
回退(Fallback)