HttpClientFactory系列二:集成Polly处理瞬态故障

前言:最近,同事在工作中遇到了使用HttpClient,有些请求超时的问题,辅导员让我下去调研一下,HttpClinet的使用方式已经改成了之前博客中提到的方式,问题的原因我已经找到了,就是因为使用了伪异步,导致阻塞主线程。在之前的博客中有园友,建议在使用静态的HttpClinet时务必使用它的Async方法,所以就得从头到尾异步化。这一点在之前的文章中没有提,这里作为补充,也感谢这位园友。关于怎么使用异步编程,在这里我就不聊了,大家可以看看其他的博客,看完公司的代码之后,我想强调的是,在使用异步编程的时候,关于返回值的问题:

为什么async方法返回的通常都是Task或者Task<T>,而不是T本身?这是因为,Task和Task<T>代表着在将来某一个时刻将会返回T类型的结果。因此,在主线程调用HttpPostWhitStrBody时,实际上你拿到的是一个未来才会发生的预期,也就是未来的某一个时间会得到一个string的结果。如果返回的是一个T本身,那么,在主线程调用时就会因为访问这个需要一段时间才能给出结果,从而阻塞了主线程。因此,如果async方法有返回值,应返回Task<T>。如果没有返回值,应该返回Task。大家如果不太明白的话,建议多了解一下C#中的异步编程。好了,前戏太多了,下面就来聊聊如何集成Polly。 

一、在异步编程中如何处理异常信息

在聊如何集成Polly前,我们先来看看在异步编程中如何处理异常。当异步操作发生异常的时候,异常会停留在异步方法中,调用方法无法直接看到,因此,我们应该异步方法中处理异常,而不是在调用方法中处理异常。如果我们使用了await修饰了任务,那么,只需要为它包上一层try-catch就可以了。当然了,也可以在调用方法(比如Main方法中)捕捉异常,这就需要异常从异步方法中传播给调用方法。做到这件事是很容易的,只需要两个条件:

(1)调用方法本身也是async的,并且,在内部调用异步方法,并使用await。

(2)异步方法返回Task或者Task<T>

因为C#不允许在Main方法中使用async(在C#7.1中,可以使用async修饰Main方法了),因此,我们不得不再创建一层方法,下面通过代码演示一下。

640?wx_fmt=png

一般在处理异常的时候,我们都是采用 try-catch来做处理的,若我们想重试三次,此时我们只能进行循环三次操作。我们只能简单进行处理,自从有了Polly,什么重试机制,超时都不在话下,下面把话题转向Polly。

在聊下面的话题时,建议大家先认真阅读一下这篇博客,因为博主讲的非常细致:Polly

 

二、集成Polly,处理HTTP请求过程中的瞬时故障

   Polly是一种流行的瞬态故障处理库,它提供了一种机制来定义可在某些故障发生时应用的策略。 最常用的策略之一就是重试策略。 这中策略允许您包装一些代码,如果发生故障,将重试这些代码; 必要时也可以重试多次。 这在您的应用程序需要与外部服务通信的情况下非常有用。 当通过HTTP与服务进行通信时,会出现瞬态故障,这种风险始终存在。 瞬态故障可能会阻碍您的请求完成,但是瞬态故障也可能是暂时性的问题。因此, 这使得在这些情况下重试成为明智的选择。

   除了重试之外,Polly还提供了许多其他类型的策略,其中许多策略可能需要与重试相结合,以构建处理故障的复杂方法。 我将在本文中介绍一些更一般的例子,但是如果你想要更全面的了解,我建议你查看一下Polly wiki。

  •   使用Polly

  ASP.NET团队与Polly的主要维护者Dylan和Joel密切合作,使得将Polly策略应用于HttpClient实例非常简单。在开始之前我们先引用下面的两个包:

  640?wx_fmt=png

   这个Microsoft.Extensions.Http.Polly包在IHttpClientBuilder上包含一个名为AddPolicyHandler的扩展方法,我们可以使用它来添加一个handler ,该handler 将使用一个Polly实例,来包装请求。 

  我们可以用这个扩展在我们的ConfigureServices 方法中,代码如下:

  

 services.AddHttpClient("github").AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)));

   在这个例子中,我们定义了一个名字为“github”的客户端,并且我们使用AddPolicyHandler 方法来添加了一种处理超时的策略,这里提供的超时策略,必须是IAsyncPolicy<HttpResponseMessage>,这个中策略在任何请求超过10s都会触发。

  •  重试策略

  如果可能的话,当我们在使用Polly时,最好的尝试是,定义一次策略并在应用相同策略的情况下共享它们,这样要更改策略,只需在一个位置进行更改。此外,它还确保仅分配策略一次。当然了,如果多个使用者希望通过相同的断路器实例运行,则需要共享诸如断路器之类的策略。不太理解,不要紧,下面看代码,体会一下。

640?wx_fmt=png

  •  瞬时错误处理

  

处理HTTP请求时,我们要处理的最常的问题就是瞬态故障。 由于这是一个常见的要求,Microsoft.Extensions.Http.Polly软件包中包含一个特定的扩展,我们可以使用它来快速设置处理瞬时故障的策略。

例如,要在指定客户端的请求发生瞬时故障时添加基本重试,我们可以按如下方式注册重试策略:

services.AddHttpClient("github").AddTransientHttpErrorPolicy(p => p.RetryAsync(3));

 

代码的含义是,所以使用命名的HttpClient,发出的请求,只要遇到错误,就会重试三次。这个AddTransientHttpErrorPolicy 方法需要一个Func<PolicyBuilder<HttpResponseMessage>, IAsyncPolicy<HttpResponseMessage>>.类型的参数。此处的PolicyBuilder将预先配置为处理HttpRequestExceptions,任何返回5xx状态代码的响应以及具有408(请求超时)状态代码的任何响应。 这应该适用于许多情况。 如果您要求在其他条件下应用策略,则需要使用不同的重载来传递更具体的策略。

  我们需要意识到, 在进行重试时,我们需要考虑幂等性。 重试HTTP GET是一种非常安全的操作。因为HTTP GET本身就是幂等性的, 如果我们调用一个方法但没有收到任何响应,我们可以安全地重试调用而不会有任何危险。 但是,请考虑如果我们重试HTTP POST请求会发生什么? 在这种情况下,我们必须更加小心,因为您的原始请求可能实际收到,但我们收到的响应却显示失败。 在这种情况下,重试可能导致数据重复或下游系统中存储的数据损坏。 在这里,您需要更多地了解下游服务在多次收到相同请求时将执行的操作。 重试是一种安全操作? 当您拥有下游服务时,更容易控制它。 例如,您可以使用一些唯一标识符来防止重复的POST。

  如果您对下游系统的控制较少,或者您知道重复的POST可能会产生负面影响,则需要更仔细地控制策略。 可能适合的做法是定义不同的命名/类型客户端。 您可以为那些没有副作用的请求创建一个,而为那些有副作用的请求创建另一个。 然后,您可以使用正确的客户端进行操作。 但是,这可能会变得有点难以管理。 更好的选择是使用AddPolicyHandler的重载,它允许我们访问HttpRequestMessage,以便可以有条件地应用策略。 那个重载看起来像这样:AddPolicyHandler(Func<HttpRequestMessage, IAsyncPolicy<HttpResponseMessage>> policySelector),您将注意到此处的policySelector委托可以访问HttpRequestMessage,并且应该返回IAsyncPolicy <HttpResponseMessage>。 我们无法访问PolicyBuilder设置来处理瞬态错误,就像我们在前面的示例中所做的那样。 如果我们想要处理常见的瞬态错误,我们需要为我们的策略定义预期条件。 为了简化这一过程,Polly项目包含一个帮助扩展,我们可以使用它来设置一个准备好处理常见瞬态错误的PolicyBuilder。 要使用扩展方法,我们需要从Nuget添加Polly.Extensions.Http包。

  然后,我们可以调用HttpPolicyExtensions.HandleTranisentHttpError()来获取配置瞬态故障条件的PolicyBuilder。 我们可以使用该PolicyBuilder创建一个合适的重试策略,当请求是HTTP GET时,可以有条件地应用该策略。 在此示例中,任何其他HTTP方法都使用NoOp策略。

640?wx_fmt=png

  •  使用PolicyRegistry

  我想在本文中介绍的最后一个示例是如何从策略注册表中应用策略。 为了支持策略重用,Polly提供了PolicyRegistry的概念,PolicyRegistry本质上是策略的容器。 这些可以在应用程序启动时通过向注册表添加策略来定义。 然后可以传递注册表并用于按名称访问策略。IHttpClientBuilder上可用的扩展还支持使用注册表将基于Polly的处理程序添加到客户端。

640?wx_fmt=png

 首先,我们必须在DI中注册PolicyRegistry。 Microsoft.Extensions.Http.Polly包中包含一些扩展方法,以简化此操作。 在上面的示例中,我调用AddPolicyRegistry方法,该方法是IServiceCollection的扩展。 这将创建一个新的PolicyRegistry,并在DI中添加注册,作为IPolicyRegistry <string>和IReadOnlyPolicyRegistry <string>的实现。 该方法返回策略,以便我们有权向其添加策略。

 在此示例中,我们添加了两个超时策略并为其指定了名称。 现在,在注册客户端时,我们可以调用IHttpClientBuilder上的AddPolicyHandlerFromRegistry方法。 这将采用我们想要使用的策略的名称。 当工厂创建此命名客户端的实例时,它将添加适当的处理程序,在“regular”重试策略中包含调用,该策略将从注册表中检索。 

示例项目:新建一个.Net Core 2.1的webapi项目:

640?wx_fmt=png

Startup.cs文件的代码:

640?wx_fmt=png

注意:

WaitAndRetryAsync参数的意思是:每次重试时等待的睡眠持续时间。

ValuesController的代码:

640?wx_fmt=png

640?wx_fmt=png

看到没,它在重试。

  更多的Polly和HttpClinetFactory的集成使用请参考:

https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory

https://www.hanselman.com/blog/AddingResilienceAndTransientFaultHandlingToYourNETCoreHttpClientWithPolly.aspx 

三、总结

  注意:AddTransientHttpErrorPolicy方法会自动帮我们处理以下错误:

  (1)Network failures (System.Net.Http.HttpRequestException)

  (2)HTTP 5XX status codes (server errors)

  (3)HTTP 408 status code (request timeout) 

  通过这些库,您可以轻松地启动并运行能够无缝处理瞬态故障的HttpClient实例。 有关更详细的Polly文档和示例,建议您查看Polly wiki。这里只是聊了关于HttpClientFactory中集成Polly的基础用法,关于更详细的使用请参考:https://www.cnblogs.com/CreateMyself/p/7589397.html,好了今天就聊到这里,该系列文章还有最后一篇,对于Polly我也是刚接触,至于项目中是否使用还要经过辅导员的审核,希望对你有帮助,谢谢。 

 参考文章:

(翻译)https://www.stevejgordon.co.uk/httpclientfactory-using-polly-for-transient-fault-handling

相关文章:

  • ASP.Net Core2.1中的HttpClientFactory系列一:HttpClient的缺陷

  • .NET Core 中正确使用 HttpClient 的姿势

  • AspNetCore 基于AOP实现Polly的使用

  • 使用.NetCore 控制台演示 熔断 降级(polly)

  • .NET Core微服务之基于Polly+AspectCore实现熔断与降级机制

  • 再探Circuit Breaker之使用Polly

  • 开源服务容错处理库Polly使用文档

  • Polly组件对微服务场景的价值

原文地址:https://www.cnblogs.com/runningsmallguo/p/9692001.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319775.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Loj#6053-简单的函数【Min25筛】

正题 题目链接:https://loj.ac/p/6053 题目大意 定义一个积性函数f(pc)pxorcf(p^c)p\ xor\ cf(pc)p xor c&#xff0c;求∑i1nf(i)\sum_{i1}^nf(i)∑i1n​f(i) 解题思路 异或这个东西不太好搞&#xff0c;要考虑怎么求出ggg数组。 当ppp为质数时f(p)p−1f(p)p-1f(p)p−1&am…

邓公数据结构C++语言版学习笔记——二叉树

二叉树的遍历 一. preorder——先序遍历VLR 1. 递归先序遍历 2. 迭代先序遍历 3.先序遍历图解 二. inorder——先序遍历LVR 1. 递归中序遍历 2.迭代中序遍历 3.迭代中序遍历优化空间复杂度 <1>定义直接后继 <2>借用直接后继优化算法 解释&#xff1a;…

二分图匹配--匈牙利算法

文章目录二分图&#xff1a;匹配匈牙利算法代码&#xff1a;二分图&#xff1a; 二分图是一个无向图&#xff0c;点集分成子集X和Y&#xff0c;图中每一条边都是一边在X一边在Y 当且仅当无向图G的每一个回路次数都是偶数时&#xff08;包括0&#xff09;&#xff0c;G就是一个…

CF757F-Team Rocket Rises Again【最短路,DAG支配树】

正题 题目链接:https://www.luogu.com.cn/problem/CF757F 题目大意 nnn个点mmm条边的一张无向图&#xff0c;求删除sss以外的一个点改变sss到最多点的最短路。 解题思路 挺裸的一道题的&#xff0c;首先肯定要跑一遍最短路搞出最短路树。 然后如果最短路树上sss到某个点的路…

星座图(2020特长生 T4)

题目大意 给你一棵树&#xff0c;距离为2的两个点代价为wi∗wjw_i*w_jwi​∗wj​&#xff0c;问你最小代价和代价之和 解题思路 搜索这棵树&#xff0c;每次拿父亲和子节点一起计算即可 代码 #include<cstdio> #include<cstring> #include<algorithm> #de…

《Office 365开发入门指南》上市说明和读者服务

写在最开始的话拙作《Office 365开发入门指南》上周开始已经正式在各大书店、在线商城上市&#xff0c;欢迎对Office 365的开发、生态感兴趣的开发者、项目经理、产品经理参考本书&#xff0c;全面了解Office 365带来的全新机遇以及在具体业务应用开发中的场景。写作本书差不多…

简单理解手机快充

浅谈手机快充 背景 智能手机发展这么些年&#xff0c;屏幕显示越来越清晰&#xff0c;拍照像素越来越高&#xff0c;处理器性能越来越强&#xff0c;运行内存甚至开始超过PC&#xff0c;不过手机的续航还是一个问题&#xff1a;处理器性能以及一系列的增强无疑对电池是一个巨…

最短路模板

文章目录dijstraSPFAdijstra #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int MAXN10010,MAXM500010; int inf2147483647; struct XY{int w,to,pre; }e[MAXM];str…

P6499-[COCI2016-2017#2]Burza【状压dp】

正题 题目链接:https://www.luogu.com.cn/problem/P6499 题目大意 nnn个点的一棵树&#xff0c;开始有一个棋子在根处&#xff0c;开始先手选择一个点封锁&#xff0c;然后后手封锁棋子所在点然后移动一步到一个没有封锁的点&#xff0c;之后轮流进行。 先手不知道后手的移动…

各种dp优化

dp优化思路 dp三要素&#xff1a; 状态、决策、转移 dp优化思路&#xff1a; 减少状态总数减少决策时间&#xff08;减少每个状态转移的状态数&#xff09;减少转移时间 矩阵优化dp &#xff08;其实质是优化 “转移”&#xff09; 博客 数据结构优化dp &#xff08;其实…

裁缝师(2011特长生 T2)

题目大意 给你一个NM的布&#xff0c;你可以将最多L块布同时剪一刀&#xff0c;问你把他全部剪成11的最少要多少刀 解题思路#1 直接从中间剪&#xff0c;然后dfs求出一个图&#xff0c;然后每次找L个点去跑 代码#1 #include<queue> #include<cstdio> #include&l…

【送书活动】C# 程序员的自我修养

如果希望成为一个C# 高手&#xff0c;或者至少是合格的C# 程序员&#xff0c;应该懂些什么&#xff1f;《C#从现象到本质》&#xff08;以下简称本书&#xff09;试图回答这个问题。实际上&#xff0c;在本书问世之前&#xff0c;市面上已经有很多优秀的C# 书籍&#xff0c;例如…

【c++算法刷题笔记】——洛谷2

1. 洛谷练习——P1579 哥德巴赫猜想&#xff08;升级版&#xff09; 题目描述&#xff1a; 现在请你编一个程序验证哥德巴赫猜想。 先给出一个奇数n&#xff0c;要求输出3个质数&#xff0c;这3个质数之和等于输入的奇数。 输入格式&#xff1a; 仅有一行&#xff0c;包含一个…

【每日一题】7月10日精讲—矩阵取数游戏

来源&#xff1a;牛客网&#xff1a; 文章目录题目描述题解&#xff1a;代码&#xff1a;时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld题目描述 帅帅经常跟同学玩一个矩阵取数游戏&…

【dfs】民生问题(2011特长生 T4)

题目大意 有n个问题&#xff0c;m个人&#xff0c;每个人可以解决一些问题&#xff0c;问最少选多少个人可以解决所有问题 解题思路 如果一个人解决的问题被别的人包括&#xff0c;那么可以把这个人丢掉 对于一个问题只能由一个人解决&#xff0c;那么直接选这个人 然后枚举…

张善友:自由之精神,中国之队长

张善友&#xff0c;毕业于兰州大学数学系&#xff0c;2006年开始连任微软最有价值专家&#xff08;MVP&#xff09;&#xff0c;一直在社区宣导.NET开源项目&#xff0c;从早期的Mono到.NET Core&#xff0c;在社区被尊称为张队长&#xff0c;在腾讯工作11年后&#xff0c;进行…

CF461D-Appleman and Complicated Task【并查集】

正题 题目链接:https://www.luogu.com.cn/problem/CF461D 题目大意 n∗nn*nn∗n的网格需要填上xxx或ooo&#xff0c;其中有kkk个格子已经固定&#xff0c;求有多少中填写方案使得每个格子的四周都有偶数个ooo。 解题思路 约束条件相当于一个格子周围的异或和都为000&#xff…

工科数学分析无穷级数总结

目录序言一.常数项级数概念1. 什么是常数项无穷级数&#xff1f;2. 级数的收敛性与和两个特别的级数级数的判别方法①常数项级数判别法②正项级数的审敛准则③变号级数的审敛准则④绝对收敛二.函数项级数概念1. 什么是函数项级数&#xff1f;2. 函数项级数处处收敛与和函数一致…

dump解析入门-用VS解析dump文件进行排障

突然有一天部署在服务器的一个应用挂掉了&#xff0c;没办法只能进入服务器打开【事件查看器】查看下&#xff0c;好不容易找到了打开后一脸懵逼事件查看器查到的内容根本对我们排障没有任何作用。在这个时候如果有对应的dump文件就能派上用场了&#xff0c;只要有dump文件就能…

关于__int128高精度运算

参考文章 使用__int128可以实现高精度运算&#xff0c;但是这种大整数无法使用函数printf输出结果&#xff0c;所以需要手写输出 #include <bits/stdc.h> using namespace std; inline __int128 read() {__int128 x0,f1;char chgetchar();while(ch<0||ch>9){if(ch…