.Net Core 商城微服務項目系列(五):使用Polly處理服務錯誤

項目進行微服務化以後,隨之而來的問題就是服務調用過程當中發生錯誤、超時等問題的時候咱們該怎麼處理,好比由於網絡的瞬時問題致使服務超時,這在我本人所在公司的項目裏是很常見的問題,當發生請求超時問題的時候,咱們但願可以自動重試,或者是在發生服務錯誤時採起必定的策略,好比限流熔斷等等。json

本篇將會使用Polly處理服務調用過程當中發生的超時問題。緩存

打開咱們的MI.Web項目,經過NuGet引用 Microsoft.Extensions.Http 和 Microsoft.Extensions.Http.Polly。網絡

在Startup中添加以下代碼:app

    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
        {
//依賴注入 services.AddSingleton
<IApiHelperService, ApiHelperService>(); services.AddSingleton<IAccountService, AccountService>(); services.AddSingleton<IPictureService, PictureService>(); services.AddOptions(); services.AddMvc(options => { options.Filters.Add<HttpGlobalExceptionFilter>(); }); services.AddMemoryCache(); services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); return services; } public static IServiceCollection AddHttpServices(this IServiceCollection services) {//註冊http服務 //services.AddHttpClient(); services.AddHttpClient("MI") .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuiBreakerPolicy()); return services; } /// <summary> /// 重試策略 /// </summary> public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); } /// <summary> /// 熔斷策略 /// </summary> private static IAsyncPolicy<HttpResponseMessage> GetCircuiBreakerPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); } }

 

這裏咱們經過Polly分別配置了重試和熔斷的策略,當發生40四、500、408(超時)問題的時候會重試6次,間隔時間2秒;熔斷策略是若是有5個請求發生500或者超時則開啓熔斷,時間是30秒,Polly能夠配置很是詳細的策略,之後有時間再專門介紹(實際上是我如今不會。。。對不起)。由於這裏Polly是結合HttpClientFactory來使用的,因此咱們須要使用上面的代碼:異步

services.AddHttpClient("MI")
                .AddPolicyHandler(GetRetryPolicy())
                .AddPolicyHandler(GetCircuiBreakerPolicy());

這裏能夠理解爲咱們建立了一個名稱爲「MI」的HttpClientFactory,而後爲其配置了重試和熔斷策略,這裏順帶提一句是,HttpClientFactory是在.net core 2.1中加入的,它解決了以前HttpClient的資源釋放不及時的痛點,以前使用HttpClient時咱們須要使用using或者建立靜態變量,前者的問題是頻繁的建立和銷燬帶來的資源損耗,不單單和對象資源,由於HttpClient還涉及到網絡資源,後者則會致使資源釋放不及時,靜態資源若是不進行處理會一直存在,而HttpClientFactory內部會緩存鏈接資源,同時會在不使用後的一段間隔時間後進行銷燬,同時內存會維護一個隊列,單例。async

添加完上面這些後咱們還須要在ConfigureServices方法中進行註冊:微服務

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCustomMvc(Configuration).AddHttpServices();
        }

我爲API的調用封裝了一個接口層:ui

    public interface IApiHelperService
    {
        Task<T> PostAsync<T>(string url, IRequest request);
        Task<T> GetAsync<T>(string url);
    }
public class ApiHelperService : IApiHelperService
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IMemoryCache cache;
        private readonly ILogger<ApiHelperService> _logger;

        public ApiHelperService(IMemoryCache cache, ILogger<ApiHelperService> _logger, IHttpClientFactory _httpClientFactory)
        {
            this._httpClientFactory = _httpClientFactory;
            this.cache = cache;
            this._logger = _logger;
        }


        /// <summary>
        /// HttpClient實現Post請求
        /// </summary>
        public async Task<T> PostAsync<T>(string url, IRequest request)
        {
            var http = _httpClientFactory.CreateClient("MI");
            //添加Token
            var token = await GetToken();
            http.SetBearerToken(token);
            //使用FormUrlEncodedContent作HttpContent
            var httpContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
            //await異步等待迴應
            var response = await http.PostAsync(url, httpContent);

            //確保HTTP成功狀態值
            response.EnsureSuccessStatusCode();

            //await異步讀取
            string Result = await response.Content.ReadAsStringAsync();

            var Item = JsonConvert.DeserializeObject<T>(Result);

            return Item;
        }
}

圖中標紅的部分就是使用帶有Polly策略的IHttpClientFactory來建立HttpClient,而後進行Post調用,Get調用也是一樣的。this

而後咱們啓動Web項目,開啓控制檯模式進行日誌查看,訪問登陸功能:url

咱們能夠看到,一共訪問了登陸方法兩次,第一次發生了404錯誤,接着自動又請求了一次,成功。

這裏只是作一次演示,接下來會在Ocelot網關中接入Polly,這樣能夠避免在每一個項目裏都進行這樣的配置,固然若是項目裏有功能須要進行特許的策略配置,是能夠採用這種方式的。

相關文章
相關標籤/搜索