本文基本是官方说明的翻译和总结(https://github.com/App-vNext/Polly)git
Polly是一款基于.NET的弹性及瞬间错误处理库, 它容许开发人员以顺畅及线程安全的方式执行重试(Retry),断路器(Circuit),超时(Timeout),隔板隔离(Bulkhead Isolation)及后背策略(Fallback)。github
Polly适用于.NET 4.0, .NET 4.5及.NET Standard 1.1(覆盖.NET Core, Mono, Xamarin.IOS, Xamarin.Android, UWP, WP 8.1+)。缓存
.NET 4.0版本安全
Install-Package Polly.Net40Async
服务器
.NET 4.5及以上版本, .Net Standard 1.1dom
Install-Package Polly
ide
Polly提供多种弹性策略。ui
程序会产生许多瞬时故障,可是在必定时间延迟以后,程序会自动纠正故障。spa
容许配置自动重试。线程
当系统发生严重故障时,快速响应请求失败比让用户等待要好。
避免故障系统过载有助于恢复系统。
当系统错误超过预配置的数量,系统将断路一段时间。
超出必定时间的等待,想要获得正确的结果是不太可能的。
保证调用者不须要等待超时。
当进程出现故障,多个失败的请求很容易占满服务器资源(线程/CPU)。
一个处于故障状态的下游系统,也会致使其上游系统故障。
将严格管控故障进程,使其使用固定大小的资源池,隔离他们对其余进程的潜在影响
必定比例的请求多是类似的。
从缓存中提供已知的响应。
当第一次读取的时候,将响应自动缓存起来。
当故障依然存在的时候,你打算作什么。
当程序依然发生故障时,执行指定操做。
不一样的故障须要不一样的策略。包装策略即组合策略。
容许灵活的将以上任意几种策略组合在一块儿。
Polly处理故障/异常有如下几个步骤。
Polly使用Policy类的泛型方法Handle指定Polly须要处理异常/故障的类型。
指定单个异常类型
Policy.Handle<DivideByZeroException>()
指定带条件的异常类型
Policy.Handle<SqlException>(ex => ex.Number == 1205)
Polly也支持指定多种异常/故障类型, 这里须要使用Or方法
Policy.Handle<DivideByZeroException>().Or<ArgumentException>()
指定多个带条件的异常类型
Policy .Handle<SqlException>(ex =ex.Number == 1205) .Or<ArgumentException>(ex =ex.ParamName == "example")
Polly也支持指定内部异常
Policy .HandleInner<HttpResponseException>() .OrInner<OperationCanceledException>(ex => ex.CancellationToken == myToken)
Polly除了支持处理异常/故障类型,还支持处理异常返回值。所谓的处理异常结果,就是当Polly监控的方法,返回某些特定结果时, Polly会触发异常/故障处理策略。
Polly使用Policy类的泛型方法HandleResult制定Polly须要处理的异常结果.
指定触发异常/故障处理策略的返回值
例如:当某个方法的返回值类型是HttpResposneMessage, 而且返回值的StatusCode是NotFound时,触发异常/故障处理策略。
Policy .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound)
指定多个返回值
Policy .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError) .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.BadGateway)
同时指定异常类型和返回值
HttpStatusCode[] httpStatusCodesWorthRetrying = { HttpStatusCode.RequestTimeout, // 408 HttpStatusCode.InternalServerError, // 500 HttpStatusCode.BadGateway, // 502 HttpStatusCode.ServiceUnavailable, // 503 HttpStatusCode.GatewayTimeout // 504 }; HttpResponseMessage result = Policy .Handle<HttpResponseException>() .OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
重试一次
Policy .Handle<DivideByZeroException>() .Retry()
重试屡次
Policy .Handle<DivideByZeroException>() .Retry(3)
重试屡次,每次重试触发一个行为
Policy .Handle<DivideByZeroException>() .Retry(3, (exception, retryCount) => { // do something });
永久重试
Policy .Handle<DivideByZeroException>() .RetryForever()
永久重试,每次重试触发一个行为
Policy .Handle<DivideByZeroException>() .RetryForever(exception => { // do something });
指定每一个重试的间隔时间
Policy .Handle<DivideByZeroException>() .WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) });
在这个例子若是第一次出现异常,会在1秒后重试,若是依然出现异常,会在再次出现异常后2秒继续重试,以此类推,下次异常后3秒继续重试
每次重试,触发一个行为
Policy .Handle<DivideByZeroException>() .WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) }, (exception, timeSpan) => { // do something });
在发生指定次数的异常/故障以后,断开回路
Policy .Handle<DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1));
发生2次异常以后,断开回路1分钟
Action<Exception, TimeSpan> onBreak = (exception, timespan) => { ... }; Action onReset = () => { ... }; CircuitBreakerPolicy breaker = Policy .Handle<DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);
发生2次异常以后,断开回路1分钟, 在触发断路时触发onBreak方法,当重置断路器时,触发onReset方法
后备策略
Policy .Handle<Whatever>() .Fallback<UserAvatar>(UserAvatar.Blank)
当程序触发异常/故障后,返回一个备用值
Policy .Handle<Whatever>() .Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar())
当程序触发异常/故障后,使用一个方法返回一个备用值
Policy .Handle<Whatever>() .Fallback<UserAvatar>(UserAvatar.Blank, onFallback: (exception, context) => { // do something });
当程序触发异常/故障后,返回一个备用值,并触发一个方法
Policy .Handle<Whatever>() .Fallback<UserAvatar>(UserAvatar.Blank, onFallback: (exception, context) => { // do something });
Polly将监控DoSomething方法,若是发生DivideByZeroException异常,就使用重试策略
var policy = Policy .Handle<DivideByZeroException>() .Retry(); policy.Execute(() => DoSomething());
向Polly上下文中传递任意值
var policy = Policy .Handle<DivideByZeroException>() .Retry(3, (exception, retryCount, context) => { var methodThatRaisedException = context["methodName"]; Log(exception, methodThatRaisedException); }); policy.Execute( () => DoSomething(), new Dictionary<string, object>() {{ "methodName", "some method" }} );