HttpClientFactory ポリシーと Polly ポリシーで指数バックオフを含む HTTP 呼び出しの再試行を実装するImplement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies

指数のバックオフでの再試行のためのアプローチとしては、オープン ソースである Polly ライブラリのような高度な .NET ライブラリを利用することをお勧めします。The recommended approach for retries with exponential backoff is to take advantage of more advanced .NET libraries like the open-source Polly library.

Polly とは、回復機能と一時的な障害処理の機能を提供する .NET ライブラリです。Polly is a .NET library that provides resilience and transient-fault handling capabilities. このような機能は、再試行、遮断器、バルクヘッド分離、タイムアウト、フォールバックなどの Polly ポリシーを適用することで実装できます。You can implement those capabilities by applying Polly policies such as Retry, Circuit Breaker, Bulkhead Isolation, Timeout, and Fallback. Polly は .NET 4.x および .NET Standard ライブラリ 1.0 (.NET Core をサポート) を対象にしています。Polly targets .NET 4.x and the .NET Standard Library 1.0 (which supports .NET Core).

ただし、HttpClient で Polly のライブラリを使用する独自のカスタム コードを作成することは非常に複雑になる可能性があります。However, writing your own custom code to use Polly’s library with HttpClient can be significantly complex. eShopOnContainers の最初のバージョンでは、ResilientHttpClient ビルディングブロックが Polly を基盤としていました。In the original version of eShopOnContainers, there was a ResilientHttpClient building-block based on Polly. ただし、HttpClientFactory がリリースされ、Polly との回復性の高い HTTP 通信がはるかに簡単に実装できるようになったため、eShopOnContainers ではビルディング ブロックが非推奨になりました。But with the release of HttpClientFactory, implementing resilient HTTP communication with Polly has become much simpler, so that building-block was deprecated from eShopOnContainers.

次の手順では、前のセクションで説明した、HttpClientFactory に統合された Polly で HTTP 再試行を使用する方法を示します。The following steps show how you can use Http retries with Polly integrated into HttpClientFactory, which is explained in the previous section.

ASP.NET Core 2.2 パッケージを参照するReference the ASP.NET Core 2.2 packages

HttpClientFactory は .NET Core 2.1 以降で使用できますが、最新の ASP.NET Core 2.2 パッケージを NuGet から入手し、プロジェクトで使用することをお勧めします。HttpClientFactory is available since .NET Core 2.1 however we recommend you to use the latest ASP.NET Core 2.2 packages from NuGet in your project. 通常、AspNetCore メタパッケージと拡張パッケージ Microsoft.Extensions.Http.Polly が必要になります。You typically need the AspNetCore metapackage, and the extension package Microsoft.Extensions.Http.Polly.

Startup で、Polly の再試行ポリシーでクライアントを構成するConfigure a client with Polly’s Retry policy, in Startup

前のセクションで示したように、標準の Startup.ConfigureServices(...) メソッドで、名前または型が指定された HttpClient 構成を定義する必要がありますが、今後は以下のように、指数バックオフを含む HTTP 再試行のポリシーを指定し、増分コードを追加します。As shown in previous sections, you need to define a named or typed client HttpClient configuration in your standard Startup.ConfigureServices(...) method, but now, you add incremental code specifying the policy for the Http retries with exponential backoff, as below:

//ConfigureServices()  - Startup.cs
services.AddHttpClient<IBasketService, BasketService>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
        .AddPolicyHandler(GetRetryPolicy());

AddPolicyHandler() メソッドは、使用する HttpClient オブジェクトにポリシーを追加します。The AddPolicyHandler() method is what adds policies to the HttpClient objects you'll use. この場合、指数バックオフを含む HTTP 再試行に対して Polly のポリシーが追加されます。In this case, it's adding a Polly’s policy for Http Retries with exponential backoff.

手法のモジュール性を高めるために、次のコードで示すように、Startup.cs ファイル内の個別メソッドに HTTP 再試行ポリシーを定義できます。To have a more modular approach, the Http Retry Policy can be defined in a separate method within the Startup.cs file, as shown in the following code:

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
                                                                    retryAttempt)));
}

Polly では、再試行回数を指定した再試行ポリシー、指数バックオフの構成、HTTP 例外が発生した場合に実行するアクション (エラーの記録など) を定義できます。With Polly, you can define a Retry policy with the number of retries, the exponential backoff configuration, and the actions to take when there's an HTTP exception, such as logging the error. 上記のコードでは、指数関数的再試行で (最初は 2 秒) 6 回試すようにポリシーが構成されています。In this case, the policy is configured to try six times with an exponential retry, starting at two seconds.

再試行ポリシーにジッタ方式を追加するAdd a jitter strategy to the retry policy

通常の再試行ポリシーは、コンカレンシーやスケーラビリティが高い場合や、高競合状態下でシステムに影響を及ぼすことがあります。A regular Retry policy can impact your system in cases of high concurrency and scalability and under high contention. 部分的な停止の場合に多くのクライアントから来る同様の再試行のピークを乗り越えるための賢い回避策は、ジッタ方式を再試行アルゴリズムまたはポリシーに追加することです。To overcome peaks of similar retries coming from many clients in case of partial outages, a good workaround is to add a jitter strategy to the retry algorithm/policy. これにより、急増するバックオフにランダム性を加えることで、エンドツーエンド システム全体のパフォーマンスを向上できます。This can improve the overall performance of the end-to-end system by adding randomness to the exponential backoff. こうすれば、問題が発生した際のスパイクを分散できます。This spreads out the spikes when issues arise. 平易な Polly ポリシーを使用する場合、ジッタを実装するコードは次の例のようになります。When you use a plain Polly policy, code to implement jitter could look like the following example:

Random jitterer = new Random(); 
Policy
  .Handle<HttpResponseException>() // etc
  .WaitAndRetry(5,    // exponential back-off plus some jitter
      retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))  
                    + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)) 
  );

その他の技術情報Additional resources