ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理

原文:https://www.stevejgordon.co.uk/httpclientfactory-using-polly-for-transient-fault-handling
发表于:2018年6月git

      在本系列的上一篇文章中,我介绍了使用命名和类型客户端注册的DelegatingHandlers的传出中间件的概念。尽管可使用该方法,但ASP.NET团队但愿在大多数状况下,咱们无需手动构建本身的处理程序。在某些状况下,库的内置功能可能会提供咱们须要的功能。例如,有时将请求包装在时序代码中以跟踪它们执行所需的时间有时会颇有用。如今,它已做为默认日志记录的一部份内置到IHttpClientFactory中。在其余状况下,第三方集成可能会提供您所需的功能。例如,基于横切面的思想,在HTTP请求期间处理瞬态故障。在这种状况下,与其制做本身的重试逻辑,不如使用Polly之类的库。
      Polly是一个流行的瞬态故障处理库,它提供了一种机制来定义在发生某些故障时能够应用的策略。重试策略是最经常使用的策略之一。您能够封装一些代码,若是发生故障,将重试这些代码,有时须要屡次重试。这在您的应用程序须要与外部服务进行通讯的状况下很是有用。经过HTTP之类的传输工具与服务进行通讯时,始终存在瞬态故障的风险。暂时性故障可能会阻止您的请求完成,但也多是暂时的问题。在这种状况下,使用重试是明智的选择。
      除重试外,Polly还提供了许多其余类型的策略,您可能但愿将其中许多策略与重试结合使用,以创建处理故障的复杂方法。我将在本文中介绍一些常见的示例,可是若是您想更全面地介绍,我建议您查看Polly Wiki。
      ASP.NET团队与Polly的主要维护者Dylan和Joel紧密合做,加入了一种集成模式,以使将Polly策略应用于HttpClient实例变得很是简单。
      在使用Polly集成以前,咱们须要为项目添加一个包引用。 IHttpClientFactory的常规功能位于Microsoft.Extensions.Http包中,该包做为依赖项包含在Microsoft.AspNetCore.App 2.1元包中。这是ASP.NET Core 2.1中新的元数据包,其中不包含第三方依赖项。所以,为了对IHttpClientFactory使用Polly扩展,咱们须要将Microsoft.Extensions.Http.Polly包添加到咱们的项目中。
      完成以后,csproj文件将以下所示:github

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.0" />
  </ItemGroup>

</Project>

应用策略

      Microsoft.Extensions.Http.Polly程序包在IHttpClientBuilder上包含一个名为AddPolicyHandler的扩展方法,咱们可使用该方法添加一个处理程序,该处理程序会将使用该客户端实例的全部请求包装在Polly策略中。当咱们定义一个命名或类型的客户端时,将返回IHttpClientBuilder。
      咱们能够在ConfigureServices方法中使用扩展方法…安全

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

  在此示例中,咱们定义了一个名为“ github”的客户端,而且使用了AddPolicyHandler方法来传递超时策略。您在此处提供的策略必须是IAsyncPolicy <HttpResponseMessage>。此政策将在10秒后使全部请求超时。app

重用策略

      在可能的状况下,使用Polly时,最好一次性的定义策略并在应用相同策略的状况下共享它们。这样,要更改策略规则,这些更改仅须要在一个地方进行。此外,它确保仅分配策略一次。固然,若是多个调用者但愿经过同一断路器实例运行,则必须共享诸如断路器之类的策略。
      在此示例中,咱们将从上一个示例中声明一次超时策略,并与两个命名的客户端共享该策略。工具

var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10));

services.AddHttpClient("github")
  .AddPolicyHandler(timeoutPolicy);

services.AddHttpClient("google")
  .AddPolicyHandler(timeoutPolicy);

  咱们将在本文后面介绍另外一种策略重用的选项,使用PolicyRegistry。ui

 瞬时故障处理

      在处理HTTP请求时,咱们要处理的最多见状况是瞬时错误。因为这是一个常见的要求,所以Microsoft.Extensions.Http.Polly软件包包括一个特定的扩展名,咱们可使用该扩展名快速设置处理瞬态故障的策略。
      例如,要在命名客户端的请求发生瞬时故障时添加基本重试,咱们能够按如下方式注册重试策略:google

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

      在这种状况下,当知足某些失败条件时,将重试经过客户端发出的全部请求。 AddTransientHttpErrorPolicy方法采用Func <PolicyBuilder <HttpResponseMessage>,IAsyncPolicy <HttpResponseMessage >>。这里的PolicyBuilder将被预先配置为处理HttpRequestExceptions,任何返回5xx状态码的响应以及任何带有408(请求超时)状态码的响应。这应该适合许多状况。若是您要求该策略在其余条件下应用,则须要使用其余重载来传递更具体的策略。
      众所周知,重试时咱们须要考虑幂等性。重试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策略。spa

var retryPolicy = HttpPolicyExtensions
  .HandleTransientHttpError()
  .RetryAsync(3);

var noOp = Policy.NoOpAsync().AsAsyncPolicy<HttpResponseMessage>();

services.AddHttpClient("github")
  .AddPolicyHandler(request => request.Method == HttpMethod.Get ? retryPolicy : noOp);

使用PolicyRegistry

      最后一个示例是如何经过策略注册表(policy registry)应用策略的基本演示。为了支持策略重用,Polly提供了PolicyRegistry的概念,该概念实质上是策略的容器。能够在应用程序启动时经过将策略添加到注册表中来定义。而后能够将注册表传递出去,并经过名称访问策略。设计

      IHttpClientBuilder的扩展方法支持使用注册表(registry)将基于Polly的处理程序添加到客户端。日志

var registry = services.AddPolicyRegistry();

var timeout = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(30));

registry.Add("regular", timeout);
registry.Add("long", longTimeout);

services.AddHttpClient("github")
	.AddPolicyHandlerFromRegistry("regular");

  首先,咱们必须经过DI注册一个PolicyRegistry。 Microsoft.Extensions.Http.Polly软件包包括一些扩展方法,可简化此过程。在上面的示例中,我调用了AddPolicyRegistry方法,该方法是IServiceCollection的扩展。这将建立一个新的PolicyRegistry并经过DI注册,做为IPolicyRegistry <string>和IReadOnlyPolicyRegistry <string>的实现。该方法返回策略,以便咱们能够向其添加策略。

      在此示例中,咱们添加了两个超时策略并为其指定了名称。如今,在注册客户端时,咱们能够调用IHttpClientBuilder上可用的AddPolicyHandlerFromRegistry方法,使用的是策略名称。当工厂建立命名客户端实例时,它会添加适当的处理程序,并调用“regular”重试策略。

总结

      做为Polly的老用户,我很高兴看到IHttpClientFactory添加了这些集成。这些库整合在一块儿,可以无缝处理瞬态故障,HttpClient实例很是容易启动和运行。我展现的示例很是基础和笼统,但我但愿它们能为如何使用和注册策略提供一个思路。有关Polly文档和示例的更多详细信息,建议您查看Polly Wiki。在设计这种集成时,与ASP.NET和Polly团队进行的一些早期讨论很是使人高兴,由于我可以提出策略注册表扩展的有用性。

相关文章
相关标签/搜索