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

本篇将会使用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. Python 命令行之旅:使用 argparse 实现 git 命令

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  2. 从Linux服务器下载上传文件

    首先要确定好哪两种的连接:Linux常用的有centors和unbantu两种版本,PC端Mac和Windows 如果在两个Linux之间传输,或Linux和Mac之间传输可以使用scp命令,类似于s ...

  3. 第10章 文档对象模型DOM 10.1 Node节点类型

    DOM是针对 HTML 和 XML 文档的一个 API(应用程序编程接口) .DOM描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分.DOM 脱胎于Netscape 及微软公司创始 ...

  4. Monad 在实际开发中的应用

    版权归作者所有,任何形式转载请联系作者. 作者:tison(来自豆瓣) 来源:https://www.douban.com/note/733279598/ Monad 在实际开发中的应用 不同的人会从 ...

  5. CodeForces 821D Okabe and City

    Okabe and City 题解: 将行和列也视为一个点. 然后从普通的点走到行/列的点的话,就代表这行/列已经被点亮了. 然后将费用为0的点建上边. 注意讨论(n,m)非亮的情况下. 代码: #i ...

  6. codeforces 284 D. Cow Program(记忆化搜索)

    题目链接:http://codeforces.com/contest/284/problem/D 题意:给出n个数,奇数次操作x,y都加上a[x],偶数次操作y加上a[x],x减去a[x],走出了范围 ...

  7. codeforces 19 D. Points(线段树+set二分)

    题目链接:http://codeforces.com/contest/19/problem/D 题意:给出3种操作:1)添加点(x,y),2)删除点(x,y),3)查询离(x,y)最近的右上方的点. ...

  8. NOIP 2016 蚯蚓 题解

    一道有趣的题目,首先想到合并果子,然而发现会超时,我们可以发现首先拿出来的切掉后比后拿出来切掉后还是还长,即满足单调递增,故建立三个队列即可. 代码 #include<bits/stdc++.h ...

  9. 【Redis】缓存穿透与缓存雪崩

    一.缓存雪崩 1.1 缓存雪崩产生的原因 1.2 解决方案 1.3 锁的方式 1.4 消息中间件 1.5 一级和二级缓存 1.6 均摊分配redis key 失效时间 二.缓存穿透 一.缓存雪崩 1. ...

  10. jquery多级树形下拉菜单

    效果图: 使用方法 (1)引入 jQuery 包,下载地址 (2)引入 zTree 包,下载地址 (3)引入 tree-select.js (4)$("#id").treeSele ...