深入理解 Polly:.NET Core 中的健壮错误处理策略
在现代软件开发中,错误处理是构建高可用、健壮系统的关键之一。尤其是当应用依赖外部服务(如 API、数据库或其他网络资源)时,临时的服务中断、超时或其他不可预见的错误都会影响应用的稳定性。为了提升系统的容错能力,Polly 成为 .NET 开发者的重要工具。Polly 是一个功能强大的 .NET 库,提供了多种常用的错误处理策略,如重试、断路器、回退等,帮助开发者在发生错误时进行优雅的恢复和处理。
本文将深入探讨 Polly 的核心功能及其在 .NET Core 中的应用,带你一步步掌握如何通过 Polly 构建健壮的错误处理机制。
1. 什么是 Polly?
Polly 是一个为 .NET 提供的开源库,旨在帮助开发者处理常见的错误处理需求。Polly 提供了一套丰富的策略,用于解决应用在与外部服务交互时可能出现的瞬时错误。它的主要功能包括:
-
重试(Retry)
-
断路器(Circuit Breaker)
-
回退(Fallback)
-
超时(Timeout)
-
并发限制(Bulkhead Isolation)
这些策略有助于在外部依赖出现问题时,保证系统能够优雅地恢复或避免过度依赖失败的服务。
2. Polly 核心策略
2.1 重试(Retry)
重试策略在遇到可恢复的错误时会自动重试失败的操作。比如,某个 HTTP 请求因为网络波动而失败,重试策略可以尝试再次发起请求,直到成功或达到最大重试次数。
示例代码:
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;public class Program
{public static async Task Main(string[] args){var policy = Policy.Handle<HttpRequestException>() // 捕获 HttpRequestException 异常.RetryAsync(3); // 重试 3 次HttpClient client = new HttpClient();await policy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode(); // 请求失败会抛出异常return response;});}
}
在上面的代码中,如果 HTTP 请求因某种原因失败,Polly 会自动重试最多 3 次。
2.2 断路器(Circuit Breaker)
断路器策略用于避免持续失败的操作对系统造成更大的影响。当一个操作连续失败多次时,断路器会启动,阻止进一步的请求执行,直到外部服务恢复正常。
示例代码:
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;public class Program
{public static async Task Main(string[] args){var policy = Policy.Handle<HttpRequestException>().CircuitBreakerAsync(2, TimeSpan.FromMinutes(1)); // 2 次失败后断路,1 分钟内不再尝试HttpClient client = new HttpClient();try{await policy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode();return response;});}catch (BrokenCircuitException){Console.WriteLine("Circuit is broken. Requests are not being executed.");}}
}
在这个例子中,如果 HTTP 请求连续失败两次,断路器就会打开,接下来的请求将不会再发送,直到 1 分钟后恢复正常。
2.3 回退(Fallback)
回退策略是在操作失败时提供一个备选方案。通常用于在外部服务调用失败时,返回默认数据或缓存内容,而不是直接报错。
示例代码:
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;public class Program
{public static async Task Main(string[] args){var fallbackPolicy = Policy.Handle<HttpRequestException>().FallbackAsync(Task.FromResult("Fallback response"), // 返回回退结果onFallbackAsync: (outcome, context) =>{Console.WriteLine("Fallback triggered due to: " + outcome.Exception?.Message);return Task.CompletedTask;});HttpClient client = new HttpClient();var result = await fallbackPolicy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode();return await response.Content.ReadAsStringAsync();});Console.WriteLine(result); // 如果失败,返回回退结果}
}
当请求失败时,FallbackAsync
会提供一个替代方案(这里是一个字符串“Fallback response”),从而避免应用崩溃。
2.4 超时(Timeout)
超时策略限制了操作的最大执行时间。如果操作超时,Polly 会自动终止该操作。
示例代码:
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;public class Program
{public static async Task Main(string[] args){var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(5)); // 设置请求最大超时时间为 5 秒HttpClient client = new HttpClient();try{var result = await timeoutPolicy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode();return await response.Content.ReadAsStringAsync();});}catch (TimeoutRejectedException){Console.WriteLine("The request timed out.");}}
}
在这个例子中,TimeoutAsync
设置了最大超时限制。如果请求没有在 5 秒内完成,将抛出 TimeoutRejectedException
。
2.5 并行限制(Bulkhead Isolation)
并行限制策略用于限制系统能够同时处理的并发操作数量。如果超过最大并发数,后续请求将被排队或拒绝。
示例代码:
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;public class Program
{public static async Task Main(string[] args){var bulkheadPolicy = Policy.BulkheadAsync(2, 4); // 最多 2 个并行请求,最多 4 个排队请求HttpClient client = new HttpClient();await Task.WhenAll(bulkheadPolicy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode();}),bulkheadPolicy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode();}));}
}
通过使用 BulkheadAsync
,你可以避免系统因过多并发请求而崩溃,限制并发请求的数量,确保系统的稳定性。
3. 策略组合与复合策略
Polly 还支持将多个策略组合成一个复合策略(Policy Wrap)。这样,你可以在一个操作中依次应用多个策略,比如先尝试重试,接着使用断路器,最后返回回退结果。
示例代码:
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;public class Program
{public static async Task Main(string[] args){var policy = Policy.Handle<HttpRequestException>().RetryAsync(3).WrapAsync(Policy.Handle<HttpRequestException>().CircuitBreakerAsync(2, TimeSpan.FromMinutes(1)));HttpClient client = new HttpClient();try{await policy.ExecuteAsync(async () =>{var response = await client.GetAsync("https://example.com");response.EnsureSuccessStatusCode();return response;});}catch (BrokenCircuitException){Console.WriteLine("The circuit is broken.");}}
}
通过 WrapAsync
,你将重试策略和断路器策略结合起来,形成一个更复杂的容错处理机制。
4. 小结
Polly 为 .NET Core 应用提供了一种简洁而强大的错误处理机制。它的策略(重试、断路器、回退等)能够有效提高系统的稳定性,减少因外部服务不可用或临时故障而导致的系统崩溃。在实际开发中,合理利用 Polly 的策略,可以大大提升系统的健壮性和容错能力。
如果你还没有开始使用 Polly,不妨尝试在项目中引入它,特别是在与外部 API 或服务交互时,它能帮助你更好地处理瞬时故障,保证系统稳定运行。