private async Task <NupkgEntry> OpenNupkgStreamAsyncCore(PackageInfo package, CancellationToken cancellationToken) { for (var retry = 0; retry != 3; ++retry) { try { using (var data = await _httpSource.GetAsync( new HttpSourceCachedRequest( package.ContentUri, "nupkg_" + package.Identity.Id + "." + package.Identity.Version, CreateCacheContext(retry)) { EnsureValidContents = stream => HttpStreamValidation.ValidateNupkg(package.ContentUri, stream) }, Logger, cancellationToken)) { return(new NupkgEntry { TempFileName = data.CacheFileName }); } } catch (TaskCanceledException) when(retry < 2) { // Requests can get cancelled if we got the data from elsewhere, no reason to warn. string message = string.Format(CultureInfo.CurrentCulture, Strings.Log_CanceledNupkgDownload, package.ContentUri); Logger.LogMinimal(message); } catch (Exception ex) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, package.ContentUri) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); if (retry == 2) { Logger.LogError(message); } else { Logger.LogMinimal(message); } } } return(null); }
private async Task <T> ProcessHttpSourceResultAsync <T>( PackageIdentity identity, string url, Func <HttpSourceResult, Task <T> > processAsync, SourceCacheContext cacheContext, ILogger logger, CancellationToken token) { for (var retry = 0; retry < 3; ++retry) { var httpSourceCacheContext = HttpSourceCacheContext.Create(cacheContext, retry); try { return(await _httpSource.GetAsync( new HttpSourceCachedRequest( url, "nupkg_" + identity.Id.ToLowerInvariant() + "." + identity.Version.ToNormalizedString(), httpSourceCacheContext) { EnsureValidContents = stream => HttpStreamValidation.ValidateNupkg(url, stream), IgnoreNotFounds = true, MaxTries = 1 }, async httpSourceResult => await processAsync(httpSourceResult), logger, token)); } catch (TaskCanceledException) when(retry < 2) { // Requests can get cancelled if we got the data from elsewhere, no reason to warn. var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_CanceledNupkgDownload, url); logger.LogMinimal(message); } catch (Exception ex) when(retry < 2) { var message = string.Format( CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, identity, url) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); logger.LogMinimal(message); } catch (Exception ex) when(retry == 2) { var message = string.Format( CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, identity, url) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); logger.LogError(message); } } return(await processAsync(null)); }
private async Task <T> ProcessHttpSourceResultAsync <T>( PackageIdentity identity, string url, Func <HttpSourceResult, Task <T> > processAsync, SourceCacheContext cacheContext, ILogger logger, CancellationToken token) { int maxRetries = _enhancedHttpRetryHelper.EnhancedHttpRetryEnabled ? _enhancedHttpRetryHelper.ExperimentalMaxNetworkTryCount : 3; for (var retry = 1; retry <= maxRetries; ++retry) { var httpSourceCacheContext = HttpSourceCacheContext.Create(cacheContext, isFirstAttempt: retry == 1); try { return(await _httpSource.GetAsync( new HttpSourceCachedRequest( url, "nupkg_" + identity.Id.ToLowerInvariant() + "." + identity.Version.ToNormalizedString(), httpSourceCacheContext) { EnsureValidContents = stream => HttpStreamValidation.ValidateNupkg(url, stream), IgnoreNotFounds = true, MaxTries = 1, IsRetry = retry > 1, IsLastAttempt = retry == maxRetries }, async httpSourceResult => await processAsync(httpSourceResult), logger, token)); } catch (TaskCanceledException) when(retry < maxRetries) { // Requests can get cancelled if we got the data from elsewhere, no reason to warn. var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_CanceledNupkgDownload, url); logger.LogMinimal(message); } catch (Exception ex) when(retry < maxRetries) { var message = string.Format( CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, identity, url) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); logger.LogMinimal(message); if (_enhancedHttpRetryHelper.EnhancedHttpRetryEnabled && ex.InnerException != null && ex.InnerException is IOException && ex.InnerException.InnerException != null && ex.InnerException.InnerException is System.Net.Sockets.SocketException) { // An IO Exception with inner SocketException indicates server hangup ("Connection reset by peer"). // Azure DevOps feeds sporadically do this due to mandatory connection cycling. // Stalling an extra <ExperimentalRetryDelayMilliseconds> gives Azure more of a chance to recover. logger.LogVerbose("Enhanced retry: Encountered SocketException, delaying between tries to allow recovery"); await Task.Delay(TimeSpan.FromMilliseconds(_enhancedHttpRetryHelper.ExperimentalRetryDelayMilliseconds)); } } catch (Exception ex) when(retry == maxRetries) { var message = string.Format( CultureInfo.CurrentCulture, Strings.Log_FailedToDownloadPackage, identity, url) + Environment.NewLine + ExceptionUtilities.DisplayMessage(ex); logger.LogError(message); } } return(await processAsync(null)); }