Skip to content

Commit be79f1c

Browse files
author
Mirroring
committed
Merge commit '6bd6e4a1b3e14b531aa634abf6acddffc8324fa8'
2 parents 77092d4 + 6bd6e4a commit be79f1c

File tree

21 files changed

+277
-14
lines changed

21 files changed

+277
-14
lines changed

src/Containers/Microsoft.NET.Build.Containers/ContainerBuilder.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ private static async Task<int> PushToLocalRegistryAsync(ILogger logger, BuiltIma
215215
await containerRegistry.LoadAsync(builtImage, sourceImageReference, destinationImageReference, cancellationToken).ConfigureAwait(false);
216216
logger.LogInformation(Strings.ContainerBuilder_ImageUploadedToLocalDaemon, destinationImageReference, containerRegistry);
217217
}
218+
catch (UnableToDownloadFromRepositoryException)
219+
{
220+
logger.LogError(Resource.FormatString(nameof(Strings.UnableToDownloadFromRepository)), sourceImageReference);
221+
return 1;
222+
}
218223
catch (Exception ex)
219224
{
220225
logger.LogError(Resource.FormatString(nameof(Strings.RegistryOutputPushFailed), ex.Message));
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Microsoft.NET.Build.Containers;
5+
6+
internal sealed class UnableToDownloadFromRepositoryException : Exception
7+
{
8+
public UnableToDownloadFromRepositoryException(string repository)
9+
: base($"The download of the image from repository { repository } has failed.")
10+
{
11+
}
12+
}

src/Containers/Microsoft.NET.Build.Containers/ImagePublisher.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ private static async Task PushToLocalRegistryAsync<T>(
107107
await loadFunc(image, sourceImageReference, destinationImageReference, cancellationToken).ConfigureAwait(false);
108108
Log.LogMessage(MessageImportance.High, Strings.ContainerBuilder_ImageUploadedToLocalDaemon, destinationImageReference, localRegistry);
109109
}
110+
catch (UnableToDownloadFromRepositoryException)
111+
{
112+
Log.LogErrorWithCodeFromResources(nameof(Strings.UnableToDownloadFromRepository), sourceImageReference);
113+
}
110114
catch (ContainerHttpException e)
111115
{
112116
Log.LogErrorFromException(e, true);

src/Containers/Microsoft.NET.Build.Containers/Registry/Registry.cs

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ internal sealed class Registry
7474
private const string DockerHubRegistry1 = "registry-1.docker.io";
7575
private const string DockerHubRegistry2 = "registry.hub.docker.com";
7676
private static readonly int s_defaultChunkSizeBytes = 1024 * 64;
77+
private const int MaxDownloadRetries = 5;
78+
private readonly Func<TimeSpan> _retryDelayProvider;
7779

7880
private readonly ILogger _logger;
7981
private readonly IRegistryAPI _registryAPI;
@@ -86,7 +88,7 @@ internal sealed class Registry
8688
/// </summary>
8789
public string RegistryName { get; }
8890

89-
internal Registry(string registryName, ILogger logger, IRegistryAPI registryAPI, RegistrySettings? settings = null) :
91+
internal Registry(string registryName, ILogger logger, IRegistryAPI registryAPI, RegistrySettings? settings = null, Func<TimeSpan>? retryDelayProvider = null) :
9092
this(new Uri($"https://{registryName}"), logger, registryAPI, settings)
9193
{ }
9294

@@ -95,15 +97,15 @@ internal Registry(string registryName, ILogger logger, RegistryMode mode, Regist
9597
{ }
9698

9799

98-
internal Registry(Uri baseUri, ILogger logger, IRegistryAPI registryAPI, RegistrySettings? settings = null) :
100+
internal Registry(Uri baseUri, ILogger logger, IRegistryAPI registryAPI, RegistrySettings? settings = null, Func<TimeSpan>? retryDelayProvider = null) :
99101
this(baseUri, logger, new RegistryApiFactory(registryAPI), settings)
100102
{ }
101103

102104
internal Registry(Uri baseUri, ILogger logger, RegistryMode mode, RegistrySettings? settings = null) :
103105
this(baseUri, logger, new RegistryApiFactory(mode), settings)
104106
{ }
105107

106-
private Registry(Uri baseUri, ILogger logger, RegistryApiFactory factory, RegistrySettings? settings = null)
108+
private Registry(Uri baseUri, ILogger logger, RegistryApiFactory factory, RegistrySettings? settings = null, Func<TimeSpan>? retryDelayProvider = null)
107109
{
108110
RegistryName = DeriveRegistryName(baseUri);
109111

@@ -117,6 +119,8 @@ private Registry(Uri baseUri, ILogger logger, RegistryApiFactory factory, Regist
117119
_logger = logger;
118120
_settings = settings ?? new RegistrySettings(RegistryName);
119121
_registryAPI = factory.Create(RegistryName, BaseUri, logger, _settings.IsInsecure);
122+
123+
_retryDelayProvider = retryDelayProvider ?? (() => TimeSpan.FromSeconds(1));
120124
}
121125

122126
private static string DeriveRegistryName(Uri baseUri)
@@ -401,26 +405,48 @@ public async Task<string> DownloadBlobAsync(string repository, Descriptor descri
401405
{
402406
cancellationToken.ThrowIfCancellationRequested();
403407
string localPath = ContentStore.PathForDescriptor(descriptor);
404-
408+
405409
if (File.Exists(localPath))
406410
{
407411
// Assume file is up to date and just return it
408412
return localPath;
409413
}
410-
411-
// No local copy, so download one
412-
using Stream responseStream = await _registryAPI.Blob.GetStreamAsync(repository, descriptor.Digest, cancellationToken).ConfigureAwait(false);
413-
414+
414415
string tempTarballPath = ContentStore.GetTempFile();
415-
using (FileStream fs = File.Create(tempTarballPath))
416+
417+
int retryCount = 0;
418+
while (retryCount < MaxDownloadRetries)
416419
{
417-
await responseStream.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
420+
try
421+
{
422+
// No local copy, so download one
423+
using Stream responseStream = await _registryAPI.Blob.GetStreamAsync(repository, descriptor.Digest, cancellationToken).ConfigureAwait(false);
424+
425+
using (FileStream fs = File.Create(tempTarballPath))
426+
{
427+
await responseStream.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
428+
}
429+
430+
// Break the loop if successful
431+
break;
432+
}
433+
catch (Exception ex)
434+
{
435+
retryCount++;
436+
if (retryCount >= MaxDownloadRetries)
437+
{
438+
throw new UnableToDownloadFromRepositoryException(repository);
439+
}
440+
441+
_logger.LogTrace("Download attempt {0}/{1} for repository '{2}' failed. Error: {3}", retryCount, MaxDownloadRetries, repository, ex.ToString());
442+
443+
// Wait before retrying
444+
await Task.Delay(_retryDelayProvider(), cancellationToken).ConfigureAwait(false);
445+
}
418446
}
419-
420-
cancellationToken.ThrowIfCancellationRequested();
421-
447+
422448
File.Move(tempTarballPath, localPath, overwrite: true);
423-
449+
424450
return localPath;
425451
}
426452

src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.resx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,10 @@
461461
<value>CONTAINER1015: Unable to access the repository '{0}' at tag '{1}' in the registry '{2}'. Please confirm that this name and tag are present in the registry.</value>
462462
<comment>{StrBegin="CONTAINER1015: "}</comment>
463463
</data>
464+
<data name="UnableToDownloadFromRepository" xml:space="preserve">
465+
<value>CONTAINER1018: Unable to download image from the repository '{0}'.</value>
466+
<comment>{StrBegins="CONTAINER1018:" }</comment>
467+
</data>
464468
<data name="UnableToAccessRepository" xml:space="preserve">
465469
<value>CONTAINER1016: Unable to access the repository '{0}' in the registry '{1}'. Please confirm your credentials are correct and that you have access to this repository and registry.</value>
466470
<comment>{StrBegin="CONTAINER1016:" }</comment>

src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.de.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.es.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.fr.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)