From 6317b34aaa798a36ff905fca77f436f875d50612 Mon Sep 17 00:00:00 2001 From: Ryan Brandenburg Date: Wed, 25 Sep 2019 13:35:14 -0700 Subject: [PATCH] Increase httpclient reliability (#14349) --- .../src/Commands/BaseCommand.cs | 57 ++++++++++++++++++- .../test/OpenApiAddURLTests.cs | 4 +- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/Tools/Microsoft.dotnet-openapi/src/Commands/BaseCommand.cs b/src/Tools/Microsoft.dotnet-openapi/src/Commands/BaseCommand.cs index 7123f0d04e..92fe39df4f 100644 --- a/src/Tools/Microsoft.dotnet-openapi/src/Commands/BaseCommand.cs +++ b/src/Tools/Microsoft.dotnet-openapi/src/Commands/BaseCommand.cs @@ -6,9 +6,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Net; +using System.Net.Http; using System.Reflection; using System.Security.Cryptography; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Microsoft.Build.Evaluation; using Microsoft.DotNet.Openapi.Tools; @@ -240,13 +243,13 @@ namespace Microsoft.DotNet.OpenApi.Commands internal async Task DownloadToFileAsync(string url, string destinationPath, bool overwrite) { - using var response = await _httpClient.GetResponseAsync(url); + using var response = await RetryRequest(() => _httpClient.GetResponseAsync(url)); await WriteToFileAsync(await response.Stream, destinationPath, overwrite); } internal async Task DownloadGivenOption(string url, CommandOption fileOption) { - using var response = await _httpClient.GetResponseAsync(url); + using var response = await RetryRequest(() => _httpClient.GetResponseAsync(url)); if (response.IsSuccessCode()) { @@ -272,6 +275,56 @@ namespace Microsoft.DotNet.OpenApi.Commands } } + /// + /// Retries every 1 sec for 60 times by default. + /// + /// + /// + /// + /// + private static async Task RetryRequest( + Func> retryBlock, + CancellationToken cancellationToken = default, + int retryCount = 60) + { + for (var retry = 0; retry < retryCount; retry++) + { + if (cancellationToken.IsCancellationRequested) + { + throw new OperationCanceledException("Failed to connect, retry canceled.", cancellationToken); + } + + try + { + var response = await retryBlock().ConfigureAwait(false); + + if (response.StatusCode == HttpStatusCode.ServiceUnavailable) + { + // Automatically retry on 503. May be application is still booting. + continue; + } + + return response; // Went through successfully + } + catch (Exception exception) + { + if (retry == retryCount - 1) + { + throw; + } + else + { + if (exception is HttpRequestException || exception is WebException) + { + await Task.Delay(1 * 1000); //Wait for a while before retry. + } + } + } + } + + throw new OperationCanceledException("Failed to connect, retry limit exceeded."); + } + private string GetUniqueFileName(string directory, string fileName, string extension) { var uniqueName = fileName; diff --git a/src/Tools/Microsoft.dotnet-openapi/test/OpenApiAddURLTests.cs b/src/Tools/Microsoft.dotnet-openapi/test/OpenApiAddURLTests.cs index 95369d7683..ff8000263d 100644 --- a/src/Tools/Microsoft.dotnet-openapi/test/OpenApiAddURLTests.cs +++ b/src/Tools/Microsoft.dotnet-openapi/test/OpenApiAddURLTests.cs @@ -440,8 +440,8 @@ namespace Microsoft.DotNet.OpenApi.Add.Tests var url = BrokenUrl; var run = app.Execute(new[] { "add", "url", url }); - Assert.Equal(_error.ToString(), $"The given url returned 'NotFound', " + - "indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine); + Assert.Equal($"The given url returned 'NotFound', " + + "indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine, _error.ToString()); Assert.Equal(1, run); var expectedJsonName = "dingos.json";