<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Flurl使用Polly實現(xiàn)重試Policy

          共 10255字,需瀏覽 21分鐘

           ·

          2021-03-16 08:21

          ?

          在使用Flurl作為HttpClient向Server請求時,由于網(wǎng)絡(luò)或者其它一些原因?qū)е抡埱髸惺〉那闆r,比如HttpStatusCode.NotFoundHttpStatusCode.ServiceUnavailable、HttpStatusCode.RequestTimeout等;網(wǎng)絡(luò)上有比較多的HttpClientFactory使用Polly來實現(xiàn)重試的內(nèi)容,奈何已經(jīng)習(xí)慣使用Flurl的人,要全部換回到IHttpClient的確有不方便的地方,因為本文使用Flurl的Polly來實現(xiàn)重試機制做一個整理;

          不使用Polly來測試

          1. 提供一個接口以便做請求測試

            [Route("api/[controller]")]
            [ApiController]
            public?class?PollyController?:?ControllerBase
            {
            ????private?readonly?ILogger<PollyController>?_logger;

            ????public?PollyController(ILogger<PollyController>?logger)
            ????{
            ????????_logger?=?logger;
            ????}

            ????//?GET:?api/<PollyController>
            ????[HttpGet]
            ????public?IActionResult?Get()
            ????{
            ????????var?random?=?new?Random().Next(0,?8);
            ????????switch?(random)
            ????????{
            ????????????case?0:
            ????????????????_logger.LogInformation("About?to?serve?a?404");
            ????????????????return?StatusCode(StatusCodes.Status404NotFound);

            ????????????case?1:
            ????????????????_logger.LogInformation("About?to?serve?a?503");
            ????????????????return?StatusCode(StatusCodes.Status503ServiceUnavailable);

            ????????????case?2:
            ????????????????_logger.LogInformation("Sleeping?for?10?seconds?then?serving?a?504");
            ????????????????Thread.Sleep(10000);
            ????????????????_logger.LogInformation("About?to?serve?a?504");
            ????????????????return?StatusCode(StatusCodes.Status504GatewayTimeout);

            ????????????default:
            ????????????????_logger.LogInformation("About?to?correctly?serve?a?200?response");
            ????????????????return?Ok(new?{time?=?DateTime.Now.ToLocalTime()});
            ????????}
            ????}
            }
          2. 創(chuàng)建一個請求客戶端

            public?class?HomeController?:?Controller
            {
            ????private?readonly?ILogger<HomeController>?_logger;

            ????public?HomeController(ILogger<HomeController>?logger)
            ????{
            ????????_logger?=?logger;
            ????}

            ????public?async?Task<IActionResult>?Index()
            ????{
            ????????try
            ????????{
            ????????????var?time?=?await?"http://127.0.0.1:5000/api/polly"
            ????????????????.GetJsonAsync();

            ????????????_logger.LogInformation($"App:?success?-?{time.time}");
            ????????????return?View(time.time);
            ????????}
            ????????catch?(Exception?e)
            ????????{
            ????????????_logger.LogWarning($"App:?failed?-?{e.Message}");
            ????????????throw;
            ????????}
            ????}
            }
          3. 嘗試請求,可以發(fā)現(xiàn)有很多請求失敗的地方,這個情況很不理想,服務(wù)器有較大的機率不能正常的響應(yīng)

            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?serve?a?404
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?correctly?serve?a?200?response
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?correctly?serve?a?200?response
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?correctly?serve?a?200?response
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?serve?a?503
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?serve?a?503
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?correctly?serve?a?200?response
            info:?SuppertRcsInterfaceTest.Controllers.PollyController[0]
            ??????About?to?serve?a?404
            ?

            針對這個情況有沒有什么解決的辦法呢,答案是肯定的,粗暴的想法就是失敗了再重新做請求,直接在Flurl的返回結(jié)果中做這個邏輯處理會比較麻煩也不方便統(tǒng)一的管理,如此就找到了Polly

          使用Polly來測試

          1. 首先安裝Polly, Install-Package Polly

          2. 下面先給出Polly的簡單介紹后接著給出Policy的代碼片段

            ?

            Polly的七種策略:重試、斷路、超時、隔離、回退和緩存策略,本文使用到了重試、超時策略

            重試(Retry):出現(xiàn)故障自動重試,這個是常見的場景

            斷路(Circuit-breaker):當(dāng)系統(tǒng)遇到嚴(yán)重的問題時,快速回饋失敗比讓用戶/調(diào)用者等待要好,限制系統(tǒng)出錯的消耗,有助于系統(tǒng)恢復(fù),比如,當(dāng)我們?nèi)フ{(diào)用一個第三方的API,有很長一段時間API都沒有響應(yīng),可能對方服務(wù)器癱瘓了,如果我們的系統(tǒng)還不停地重試,不僅會加重系統(tǒng)的負(fù)擔(dān),還有可能導(dǎo)致系統(tǒng)其它任務(wù)受影響,因此,當(dāng)系統(tǒng)出錯的次數(shù)超過了指定的閾值,就得中斷當(dāng)前線程,等待一段時間后再繼續(xù);比如: Policy.Handle<SomeException>().CircuitBreaker(2, TimeSpan.FromMinutes(1));表示當(dāng)系統(tǒng)出現(xiàn)兩次某個異常時就停下來,等待1分鐘后再繼續(xù),還可以在斷路時定義中斷的回調(diào)和重啟的回調(diào)。

            超時(Timeout):當(dāng)系統(tǒng)超過一定時間的等待,就可以判斷不可能會有成功的結(jié)果;比如平時一個網(wǎng)絡(luò)請求瞬間就完成了,如果有一次網(wǎng)絡(luò)請求超過了30秒還沒有完成,我們就可以判定不可能會返回成功的結(jié)果了,因此,我們需要設(shè)置系統(tǒng)的超時時間,避免系統(tǒng)長時間無謂的等待;比如:Policy.Timeout(30, (context, span, task) => {// do something});表示設(shè)置了超時時間不能超過30秒,否則就認(rèn)為是錯誤的結(jié)果,并執(zhí)行回調(diào)。

            隔離(Bulkhead Isolation):當(dāng)系統(tǒng)的一處出現(xiàn)故障時,可能觸發(fā)多個失敗的調(diào)用,對資源有較大的消耗,下游系統(tǒng)出現(xiàn)故障可能導(dǎo)致上游的故障的調(diào)用,甚至可能蔓延到導(dǎo)致系統(tǒng)崩潰,所以要將可控的操作限制在一個固定大小的資源池中,以隔離有潛在可能相互影響的操作;比如:Policy.Bulkhead(12, context => {// do something});表示最多允許12個線程并發(fā)執(zhí)行,如果執(zhí)行被拒絕,則執(zhí)行回調(diào)。

            回退(Fallback):有些錯誤無法避免,就要有備用的方案,當(dāng)無法避免的錯誤發(fā)生時,我們要有一個合理的返回來代替失敗;比如:Policy.Handle<Whatever>().Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar());表示當(dāng)用戶沒有上傳頭像時,我們就給他一個默認(rèn)頭像。

            緩存(Cache):一般我們會把頻繁使用且不會怎么變化的資源緩存起來,以提高系統(tǒng)的響應(yīng)速度,如果不對緩存資源的調(diào)用進行封裝,那么我們調(diào)用的時候就要先判斷緩存中有沒有這個資源,有的話就從緩存返回,否則就從資源存儲的地方獲取后緩存起來再返回,而且有時還要考慮緩存過期和如何更新緩存的問題;Polly提供了緩存策略的支持,使得問題變得簡單。

            策略包(Policy Wrap):一種操作會有多種不同的故障,而不同的故障處理需要不同的策略,這些不同的策略必須包在一起,作為一個策略包,才能應(yīng)用在同一種操作上,這就是Polly的彈性特性,即各種不同的策略能夠靈活地組合起來

            更多...

            using?System;
            using?System.Linq;
            using?System.Net;
            using?System.Net.Http;
            using?System.Threading;
            using?System.Threading.Tasks;
            using?Flurl.Http.Configuration;
            using?Microsoft.Extensions.Logging;
            using?Polly;
            using?Polly.Retry;
            using?Polly.Timeout;
            using?Polly.Wrap;

            namespace?WithPollyClient.Services
            {
            ????public?class?Policies
            ????{
            ????????private?readonly?ILogger<Policies>?_logger;

            ????????public?Policies(ILogger<Policies>?logger)
            ????????{
            ????????????_logger?=?logger;
            ????????}
            ????????
            ????????private?AsyncTimeoutPolicy<HttpResponseMessage>?TimeoutPolicy
            ????????{
            ????????????get
            ????????????{
            ????????????????return?Policy.TimeoutAsync<HttpResponseMessage>(3,?(context,?span,?task)?=>
            ????????????????{
            ????????????????????_logger.LogInformation($"Policy:?Timeout?delegate?fired?after?{span.Seconds}?seconds");
            ????????????????????return?Task.CompletedTask;
            ????????????????});
            ????????????}
            ????????}

            ????????private?AsyncRetryPolicy<HttpResponseMessage>?RetryPolicy
            ????????{
            ????????????get
            ????????????{
            ????????????????HttpStatusCode[]?retryStatus?=
            ????????????????{
            ????????????????????HttpStatusCode.NotFound,
            ????????????????????HttpStatusCode.ServiceUnavailable,
            ????????????????????HttpStatusCode.RequestTimeout
            ????????????????};
            ????????????????return?Policy
            ????????????????????.HandleResult<HttpResponseMessage>(r?=>?retryStatus.Contains(r.StatusCode))
            ????????????????????.Or<TimeoutRejectedException>()
            ????????????????????.WaitAndRetryAsync(new[]
            ????????????????????{
            ????????????????????????//?表示重試3次,第一次1秒后重試,第二次2秒后重試,第三次4秒后重試
            ????????????????????????TimeSpan.FromSeconds(1),
            ????????????????????????TimeSpan.FromSeconds(2),
            ????????????????????????TimeSpan.FromSeconds(4)
            ????????????????????},?(result,?span,?count,?context)?=>
            ????????????????????{
            ????????????????????????_logger.LogInformation($"Policy:?Retry?delegate?fired,?attempt?{count}");
            ????????????????????});
            ????????????}
            ????????}

            ????????public?AsyncPolicyWrap<HttpResponseMessage>?PolicyStrategy?=>
            ????????????Policy.WrapAsync(RetryPolicy,?TimeoutPolicy);
            ????}

            ????public?class?PolicyHandler?:?DelegatingHandler
            ????{
            ????????private?readonly?Policies?_policies;

            ????????public?PolicyHandler(Policies?policies)
            ????????{
            ????????????_policies?=?policies;
            ????????}
            ????????
            ????????protected?override?Task<HttpResponseMessage>?SendAsync(HttpRequestMessage?request,?CancellationToken?cancellationToken)
            ????????{
            ????????????return?_policies.PolicyStrategy.ExecuteAsync(ct?=>?base.SendAsync(request,?ct),?cancellationToken);
            ????????}
            ????}

            ????public?class?PollyHttpClientFactory?:?DefaultHttpClientFactory
            ????{
            ????????private?readonly?Policies?_policies;

            ????????public?PollyHttpClientFactory(Policies?policies)
            ????????{
            ????????????_policies?=?policies;
            ????????}
            ????????
            ????????public?override?HttpMessageHandler?CreateMessageHandler()
            ????????{
            ????????????return?new?PolicyHandler(_policies)
            ????????????{
            ????????????????InnerHandler?=?base.CreateMessageHandler()
            ????????????};
            ????????}
            ????}
            }
          3. 接下來在Starup中對Flurl進行配置

            public?void?ConfigureServices(IServiceCollection?services)
            {
            ????services.AddControllersWithViews();
            ????services.AddSingleton<Policies>();
            }

            //?This?method?gets?called?by?the?runtime.?Use?this?method?to?configure?the?HTTP?request?pipeline.
            public?void?Configure(IApplicationBuilder?app,?IWebHostEnvironment?env)
            {
            ????var?policies?=?app.ApplicationServices.GetService<Policies>();
            ????FlurlHttp.Configure(setting?=>
            ????????????????????????setting.HttpClientFactory?=?new?PollyHttpClientFactory(policies));
            ????......
          4. 再次嘗試請求,可以看到結(jié)果非常之理想

            WithPollyClient.Services.Policies:?Information:?Policy:?Retry?delegate?fired,?attempt?1
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:14
            WithPollyClient.Services.Policies:?Information:?Policy:?Retry?delegate?fired,?attempt?1
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:17
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:22
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:23
            WithPollyClient.Services.Policies:?Information:?Policy:?Retry?delegate?fired,?attempt?1
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:25
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:31
            WithPollyClient.Services.Policies:?Information:?Policy:?Retry?delegate?fired,?attempt?1
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:34
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:39
            WithPollyClient.Services.Policies:?Information:?Policy:?Retry?delegate?fired,?attempt?1
            WithPollyClient.Services.Policies:?Information:?Policy:?Timeout?delegate?fired?after?3?seconds
            WithPollyClient.Services.Policies:?Information:?Policy:?Retry?delegate?fired,?attempt?2
            WithPollyClient.Controllers.HomeController:?Information:?App:?success?-?2021/3/14?16:50:46

          富客戶端中使用的情況

          ?

          有時候呢,例如在WPF或者是其它的富客戶端上面也會經(jīng)常使用到Flurl的情況,如下

          var?time?=?await?Policy
          ????.Handle<FlurlHttpException>()
          ????.OrResult<IFlurlResponse>(r?=>?!r.ResponseMessage.IsSuccessStatusCode)
          ????.WaitAndRetryAsync(new[]
          ???????????????????????{
          ???????????????????????????TimeSpan.FromSeconds(1),
          ???????????????????????????TimeSpan.FromSeconds(2),
          ???????????????????????????TimeSpan.FromSeconds(4)
          ???????????????????????},?(result,?span,?count,?context)?=>
          ???????????????????????{
          ???????????????????????????_logger.LogInformation(count.ToString());
          ???????????????????????})
          ????.ExecuteAsync(()?=>?"http://127.0.0.1:5000/api/polly".WithTimeout(3).GetAsync())
          ????.ReceiveJson();

          _logger.LogInformation($"App:?success?-?{time.time}");
          return?View(time.time);

          ?

          時間如流水,只能流去不流回。

          • 公眾號:Dotnet9
          • 號主微信號:dotnet9
          • 作者:非法關(guān)鍵字
          • 原文:Flurl使用Polly添加重試機制
          • 編輯:沙漠之盡頭的狼
          • 日期:2021-03-15
          微信公眾號:Dotnet9


          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  少妇AV电影了 | 2024无码视频 | 色老扳AV| 欧美日韩一| 97日本操 |