项目进行微服务化之后,随之而来的问题就是服务调用过程中发生错误、超时等问题的时候我们该怎么处理,比如因为网络的瞬时问题导致服务超时,这在我本人所在公司的项目里是很常见的问题,当发生请求超时问题的时候,我们希望能够自动重试,或者是在发生服务错误时采取一定的策略,比如限流熔断等等。

本篇将会使用Polly处理服务调用过程中发生的超时问题。

打开我们的MI.Web项目,通过NuGet引用 Microsoft.Extensions.Http 和 Microsoft.Extensions.Http.Polly。

在Startup中添加如下代码:

    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(, retryAttempt => TimeSpan.FromSeconds(Math.Pow(, retryAttempt)));
} /// <summary>
/// 熔断策略
/// </summary>
private static IAsyncPolicy<HttpResponseMessage> GetCircuiBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(, TimeSpan.FromSeconds());
}
}

这里我们通过Polly分别配置了重试和熔断的策略,当发生404、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内部会缓存连接资源,同时会在不使用后的一段间隔时间后进行销毁,同时内存会维护一个队列,单例。

添加完上面这些后我们还需要在ConfigureServices方法中进行注册:

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

我为API的调用封装了一个接口层:

    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调用也是同样的。

然后我们启动Web项目,开启控制台模式进行日志查看,访问登录功能:

我们可以看到,一共访问了登录方法两次,第一次发生了404错误,接着自动又请求了一次,成功。

这里只是做一次演示,接下来会在Ocelot网关中接入Polly,这样可以避免在每个项目里都进行这样的配置,当然如果项目里有功能需要进行特许的策略配置,是可以采用这种方式的。

 

.Net Core 商城微服务项目系列(五):使用Polly处理服务错误的更多相关文章

  1. .Net Core 商城微服务项目系列(一):使用IdentityServer4构建基础登录验证

    这里第一次搭建,所以IdentityServer端比较简单,后期再进行完善. 1.新建API项目MI.Service.Identity,NuGet引用IdentityServer4,添加类InMemo ...

  2. .Net Core 商城微服务项目系列(六):搭建自己的Nuget包服务器

    当我们使用微服务架构之后,紧接而来的问题便是服务之间的程序集引用问题,可能没接触过的同学不太理解这句话,都已经微服务化了为什么还要互相引用程序集,当然可以不引用.但是我们会有这样一种情况,我们的每个接 ...

  3. .Net Core 商城微服务项目系列(十):使用SkyWalking构建调用链监控(2019-02-13 13:25)

    SkyWalking的安装和简单使用已经在前面一篇介绍过了,本篇我们将在商城中添加SkyWalking构建调用链监控. 顺带一下怎么把ES设置为Windows服务,cd到ES的bin文件夹,运行ela ...

  4. .Net Core 商城微服务项目系列(二):使用Ocelot + Consul构建具备服务注册和发现功能的网关

    1.服务注册 在上一篇的鉴权和登录服务中分别通过NuGet引用Consul这个包,同时新增AppBuilderExtensions类: public static class AppBuilderEx ...

  5. .Net Core 商城微服务项目系列(十一):MQ消费端独立为Window服务+消息处理服务

    之前使用MQ的时候是通过封装成dll发布Nuget包来使用,消息的发布和消费都耦合在使用的站点和服务里,这样会造成两个问题: 1.增加服务和站点的压力,因为每次消息的消费就意味着接口的调用,这部分的压 ...

  6. 微服务项目开发学成在线_day01_CMS服务端开发

    05-CMS需求分析-什么是CMS 什么是CMS?CMS (Content Management System)即内容管理系统,不同的项目对CMS的定位不同.CMS有哪些类型? 每个公司对每个项目的C ...

  7. Windows服务项目打包成安装包(Windows服务)-----------VS2017项目程序打包成.msi或者.exe

    VS2017项目程序打包成.msi或者.exe Windows服务项目使用VS2017项目程序打包成.msi或者.exe安装包 项目打包成安装包(Windows服务) 1.安装打包插件:Microso ...

  8. .Net Core 商城微服务项目系列(十五): 构建定时任务调度和消息队列管理系统

    一.系统描述 嗨,好久不见各位老哥,最近有点懒,技术博客写的太少了,因为最近在写小说,写的顺利的话说不定就转行了,哈哈哈哈哈哈哈哈哈. 今天要介绍的是基于.Net Core的定时任务调度和消息队列管理 ...

  9. .Net Core 商城微服务项目系列(十四):分布式部署携程Apollo构建配置中心

    一.开场白 在系统设计里我们有很多配置希望独立于系统之外,而又能够被系统实时读取.但是在传统的系统设计里,配置信息通常是耦合在系统内的,比如.net里通常会放在App.config或者web.conf ...

随机推荐

  1. J-Subarray_2019牛客暑期多校训练营(第二场)

    题意 有一个只由1,-1组成的数组,给出所有连续的1所在位置,求满足1的个数大于-1的个数的子区间的数量 题解 参考博客:https://www.cnblogs.com/Yinku/p/1122149 ...

  2. CFdiv2 165E. Compatible Numbers 子集枚举

    传送门 题意: 给出一个序列,输出每个数x对应的一个ans,要求ans在数列中,并且ans & x  = 0:数列的每个数小于(4e6) 思路: 这道题的方向比较难想.想到了就比较轻松了,可以 ...

  3. lightoj 1068 - Investigation(数位dp)

    An integer is divisible by 3 if the sum of its digits is also divisible by 3. For example, 3702 is d ...

  4. Period UVALive - 3026

    For each prefix of a given string S with N characters (each character has an ASCII code between 97 a ...

  5. CF981B Businessmen Problems map 模拟 二十二

    Businessmen Problems time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  6. 现代 JavaScript 教程到底是什么?

    手册与规范 <现代 JavaScript 教程>是开源的现代 JavaScript 从入门到进阶的优质教程,它旨在帮助你逐渐掌握 JavaScript 这门语言.但是一旦你已经熟悉了这门语 ...

  7. Visual Studio 调试 —— 附加到进程(远程服务器)

    一般在部署环境下不会有 Visual Studio 开发工具的,所以需要有 Remote Debugger(远程调试器) 才可以进行远程调试. Remote Debugger 获取 方法一:Visua ...

  8. pip的使用

    目录 一.配置pip环境变量 二.Cmd终端使用pip 三.Pycharm使用pip 四.Jupyter使用pip 如果把python假想成一部手机,那么pip就是这部手机上的应用管家/APP,他可以 ...

  9. Swift从入门到精通第十一篇 - 初始化 初识

    初始化(学习笔记) 环境Xcode 11.0 beta4 swift 5.1 初始化 初始化是类.结构体.枚举生成实例的过程,为该类的每个存储属性设置初始值,有些在实例使用前的设置或初始化也可在此实现 ...

  10. 5.1、顺序队列(java实现)

    1.实现代码 public class SeqQueue { private final int MaxSize = 8; private int rear; //队尾指针 private int f ...