From fa477b9e47856b36fb4571f483544c42e6d3919d Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Fri, 5 Feb 2021 21:29:21 +0300 Subject: [PATCH] implement timeout for singleton HttpClient #7618 --- .../Volo/Abp/Cli/Http/CliHttpClient.cs | 8 +- .../Volo/Abp/Cli/Http/CliHttpClientFactory.cs | 51 +++++++-- .../ProjectBuilding/AbpIoSourceCodeStore.cs | 101 ++++++++---------- .../MyGetPackageListFinder.cs | 28 +++-- .../ProjectModification/NpmPackagesUpdater.cs | 23 ++-- 5 files changed, 125 insertions(+), 86 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs index 1122648ff2..5aaf2ae2d3 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs @@ -67,7 +67,12 @@ namespace Volo.Abp.Cli.Http }; } - cancellationToken ??= CancellationToken.None; + if (cancellationToken == null) + { + var cancellationTokenSource = new CancellationTokenSource(); + cancellationTokenSource.CancelAfter(DefaultTimeout); + cancellationToken = cancellationTokenSource.Token; + } return await HttpPolicyExtensions .HandleTransientHttpError() @@ -95,5 +100,6 @@ namespace Volo.Abp.Cli.Http .ExecuteAsync(async () => await this.GetAsync(url, cancellationToken.Value)); } + } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClientFactory.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClientFactory.cs index 3748e8e64a..b509a1614d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClientFactory.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClientFactory.cs @@ -1,5 +1,7 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.Cli.Http { @@ -7,32 +9,67 @@ namespace Volo.Abp.Cli.Http { private static CliHttpClient _authenticatedHttpClient; private static CliHttpClient _unauthenticatedHttpClient; + private readonly ICancellationTokenProvider _cancellationTokenProvider; - public CliHttpClient CreateClient(bool needsAuthentication = true) + public CliHttpClientFactory(ICancellationTokenProvider cancellationTokenProvider) + { + _cancellationTokenProvider = cancellationTokenProvider; + } + + public CliHttpClient CreateClient(bool needsAuthentication = true, TimeSpan? timeout = null) { if (needsAuthentication) { - return CreateAuthenticatedHttpClient(); + return CreateAuthenticatedHttpClient(timeout); } - return CreateUnAuthenticatedHttpClient(); + return CreateUnAuthenticatedHttpClient(timeout); + } + + public CancellationToken GetCancellationToken(TimeSpan? timeout = null) + { + if (timeout == null) + { + if (_cancellationTokenProvider == null) + { + var cancellationTokenSource = new CancellationTokenSource(); + cancellationTokenSource.CancelAfter(CliHttpClient.DefaultTimeout); + return cancellationTokenSource.Token; + } + else + { + return _cancellationTokenProvider.Token; + } + } + else + { + var cancellationTokenSource = new CancellationTokenSource(); + cancellationTokenSource.CancelAfter(Convert.ToInt32(timeout.Value.TotalMilliseconds)); + return cancellationTokenSource.Token; + } } - private static CliHttpClient CreateAuthenticatedHttpClient() + private static CliHttpClient CreateAuthenticatedHttpClient(TimeSpan? timeout = null) { if (_authenticatedHttpClient == null) { - _authenticatedHttpClient = new CliHttpClient(setBearerToken: true); + _authenticatedHttpClient = new CliHttpClient(setBearerToken: true) + { + Timeout = System.Threading.Timeout.InfiniteTimeSpan + }; } return _authenticatedHttpClient; } - private static CliHttpClient CreateUnAuthenticatedHttpClient() + private static CliHttpClient CreateUnAuthenticatedHttpClient(TimeSpan? timeout = null) { if (_unauthenticatedHttpClient == null) { - _unauthenticatedHttpClient = new CliHttpClient(setBearerToken: false); + _unauthenticatedHttpClient = new CliHttpClient(setBearerToken: false) + { + Timeout = System.Threading.Timeout.InfiniteTimeSpan + }; } return _unauthenticatedHttpClient; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs index 4d4a8726a8..bebe44542d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs @@ -9,6 +9,7 @@ using System.Net.Http; using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Cli.Http; using Volo.Abp.Cli.ProjectBuilding.Templates.App; @@ -28,22 +29,23 @@ namespace Volo.Abp.Cli.ProjectBuilding public ILogger Logger { get; set; } protected AbpCliOptions Options { get; } - protected IJsonSerializer JsonSerializer { get; } - protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } - protected ICancellationTokenProvider CancellationTokenProvider { get; } + private readonly CliHttpClientFactory _cliHttpClientFactory; + public AbpIoSourceCodeStore( IOptions options, IJsonSerializer jsonSerializer, IRemoteServiceExceptionHandler remoteServiceExceptionHandler, - ICancellationTokenProvider cancellationTokenProvider) + ICancellationTokenProvider cancellationTokenProvider, + CliHttpClientFactory cliHttpClientFactory) { JsonSerializer = jsonSerializer; RemoteServiceExceptionHandler = remoteServiceExceptionHandler; CancellationTokenProvider = cancellationTokenProvider; + _cliHttpClientFactory = cliHttpClientFactory; Options = options.Value; Logger = NullLogger.Instance; @@ -134,24 +136,17 @@ namespace Volo.Abp.Cli.ProjectBuilding try { - using (var client = new CliHttpClient(TimeSpan.FromMinutes(10))) + var client = _cliHttpClientFactory.CreateClient(); + var stringContent = new StringContent( + JsonSerializer.Serialize(new GetLatestSourceCodeVersionDto { Name = name, IncludePreReleases = includePreReleases }), + Encoding.UTF8, + MimeTypes.Application.Json + ); + + using (var response = await client.PostAsync(url, stringContent, _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)))) { - var response = await client.PostAsync( - url, - new StringContent( - JsonSerializer.Serialize( - new GetLatestSourceCodeVersionDto { Name = name, IncludePreReleases = includePreReleases } - ), - Encoding.UTF8, - MimeTypes.Application.Json - ), - CancellationTokenProvider.Token - ); - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); - var result = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(result).Version; } } @@ -164,32 +159,25 @@ namespace Volo.Abp.Cli.ProjectBuilding private async Task GetTemplateNugetVersionAsync(string name, string type, string version) { - var url = $"{CliUrls.WwwAbpIo}api/download/{type}/get-nuget-version/"; - try { - using (var client = new CliHttpClient(TimeSpan.FromMinutes(10))) - { - var response = await client.PostAsync( - url, - new StringContent( - JsonSerializer.Serialize( - new GetTemplateNugetVersionDto { Name = name, Version = version} - ), - Encoding.UTF8, - MimeTypes.Application.Json - ), - CancellationTokenProvider.Token - ); + var url = $"{CliUrls.WwwAbpIo}api/download/{type}/get-nuget-version/"; + var client = _cliHttpClientFactory.CreateClient(); - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + var stringContent = new StringContent( + JsonSerializer.Serialize(new GetTemplateNugetVersionDto { Name = name, Version = version }), + Encoding.UTF8, + MimeTypes.Application.Json + ); + using (var response = await client.PostAsync(url, stringContent, _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)))) + { + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); var result = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(result).Version; } } - catch (Exception ex) + catch (Exception) { return null; } @@ -203,36 +191,35 @@ namespace Volo.Abp.Cli.ProjectBuilding try { - using (var client = new CliHttpClient(TimeSpan.FromMinutes(10))) - { + var client = _cliHttpClientFactory.CreateClient(); - if (input.TemplateSource.IsNullOrWhiteSpace()) - { - responseMessage = await client.PostAsync( - url, - new StringContent(JsonSerializer.Serialize(input), Encoding.UTF8, MimeTypes.Application.Json), - CancellationTokenProvider.Token - ); - } - else - { - responseMessage = await client.GetAsync(input.TemplateSource, CancellationTokenProvider.Token); - } + if (input.TemplateSource.IsNullOrWhiteSpace()) + { + responseMessage = await client.PostAsync( + url, + new StringContent(JsonSerializer.Serialize(input), Encoding.UTF8, MimeTypes.Application.Json), + _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)) + ); + } + else + { + responseMessage = await client.GetAsync(input.TemplateSource, _cliHttpClientFactory.GetCancellationToken()); + } - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); + var resultAsBytes = await responseMessage.Content.ReadAsByteArrayAsync(); + responseMessage.Dispose(); - return await responseMessage.Content.ReadAsByteArrayAsync(); - } + return resultAsBytes; } catch (Exception ex) { - Console.WriteLine("Error occured while downloading source-code from {0} : {1}{2}{3}", - url, responseMessage?.ToString(), Environment.NewLine, ex.Message); + Console.WriteLine("Error occured while downloading source-code from {0} : {1}{2}{3}", url, responseMessage?.ToString(), Environment.NewLine, ex.Message); throw; } } - private bool IsNetworkSource(string source) + private static bool IsNetworkSource(string source) { return source.ToLower().StartsWith("http"); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs index 75e9156ce0..5434ede83f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/MyGetPackageListFinder.cs @@ -6,17 +6,23 @@ using Microsoft.Extensions.Logging.Abstractions; using Newtonsoft.Json; using Volo.Abp.Cli.Http; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.Cli.ProjectModification { public class MyGetPackageListFinder : ISingletonDependency { - private MyGetApiResponse _response; - public ILogger Logger { get; set; } - public MyGetPackageListFinder() + private MyGetApiResponse _response; + private readonly CliHttpClientFactory _cliHttpClientFactory; + protected ICancellationTokenProvider CancellationTokenProvider { get; } + + public MyGetPackageListFinder(CliHttpClientFactory cliHttpClientFactory, + ICancellationTokenProvider cancellationTokenProvider) { + _cliHttpClientFactory = cliHttpClientFactory; + CancellationTokenProvider = cancellationTokenProvider; Logger = NullLogger.Instance; } @@ -29,18 +35,20 @@ namespace Volo.Abp.Cli.ProjectModification try { - using (var client = new CliHttpClient(TimeSpan.FromMinutes(10))) + var client = _cliHttpClientFactory.CreateClient(); + + using (var responseMessage = await client.GetAsync( + $"{CliUrls.WwwAbpIo}api/myget/packages/", + _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)))) { - var responseMessage = await client.GetAsync( - $"{CliUrls.WwwAbpIo}api/myget/packages/" + _response = JsonConvert.DeserializeObject( + Encoding.Default.GetString(await responseMessage.Content.ReadAsByteArrayAsync()) ); - - _response = JsonConvert.DeserializeObject(Encoding.Default.GetString(await responseMessage.Content.ReadAsByteArrayAsync())); } } - catch (Exception) + catch (Exception ex) { - Logger.LogError("Unable to get latest preview version."); + Logger.LogError("Unable to get latest preview version. Error: " + ex.Message); throw; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index 8fc800c146..bf23bc3786 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -27,15 +27,18 @@ namespace Volo.Abp.Cli.ProjectModification private readonly PackageJsonFileFinder _packageJsonFileFinder; private readonly NpmGlobalPackagesChecker _npmGlobalPackagesChecker; private readonly Dictionary _fileVersionStorage = new Dictionary(); + private readonly CliHttpClientFactory _cliHttpClientFactory; public NpmPackagesUpdater( PackageJsonFileFinder packageJsonFileFinder, NpmGlobalPackagesChecker npmGlobalPackagesChecker, - ICancellationTokenProvider cancellationTokenProvider) + ICancellationTokenProvider cancellationTokenProvider, + CliHttpClientFactory cliHttpClientFactory) { _packageJsonFileFinder = packageJsonFileFinder; _npmGlobalPackagesChecker = npmGlobalPackagesChecker; CancellationTokenProvider = cancellationTokenProvider; + _cliHttpClientFactory = cliHttpClientFactory; Logger = NullLogger.Instance; } @@ -151,16 +154,14 @@ namespace Volo.Abp.Cli.ProjectModification { try { - using (var client = new CliHttpClient(TimeSpan.FromMinutes(1))) + var client = _cliHttpClientFactory.CreateClient(); + using (var response = await client.GetHttpResponseMessageWithRetryAsync( + url: $"{CliUrls.WwwAbpIo}api/myget/apikey/", + cancellationToken: CancellationTokenProvider.Token, + logger: Logger + )) { - using (var response = await client.GetHttpResponseMessageWithRetryAsync( - url: $"{CliUrls.WwwAbpIo}api/myget/apikey/", - cancellationToken: CancellationTokenProvider.Token, - logger: Logger - )) - { - return Encoding.Default.GetString(await response.Content.ReadAsByteArrayAsync()); - } + return Encoding.Default.GetString(await response.Content.ReadAsByteArrayAsync()); } } catch (Exception) @@ -356,7 +357,7 @@ namespace Volo.Abp.Cli.ProjectModification protected virtual string ExtractVersions(string output) { var arrayStart = output.IndexOf('['); - return output.Substring(arrayStart, output.IndexOf(']') - arrayStart + 1); + return output.Substring(arrayStart, output.IndexOf(']') - arrayStart + 1); } protected virtual bool SpecifiedVersionExists(string version, JProperty package)