Skip to content

Commit e7d536c

Browse files
author
v-wuzhai
authored
[automated] Merge branch 'release/8.0.4xx' => 'release/9.0.1xx' (#49250)
2 parents 7a186ee + a6d6d97 commit e7d536c

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
@@ -216,6 +216,11 @@ private static async Task<int> PushToLocalRegistryAsync(ILogger logger, BuiltIma
216216
await containerRegistry.LoadAsync(builtImage, sourceImageReference, destinationImageReference, cancellationToken).ConfigureAwait(false);
217217
logger.LogInformation(Strings.ContainerBuilder_ImageUploadedToLocalDaemon, destinationImageReference, containerRegistry);
218218
}
219+
catch (UnableToDownloadFromRepositoryException)
220+
{
221+
logger.LogError(Resource.FormatString(nameof(Strings.UnableToDownloadFromRepository)), sourceImageReference);
222+
return 1;
223+
}
219224
catch (Exception ex)
220225
{
221226
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
@@ -75,6 +75,8 @@ internal sealed class Registry
7575
private const string DockerHubRegistry1 = "registry-1.docker.io";
7676
private const string DockerHubRegistry2 = "registry.hub.docker.com";
7777
private static readonly int s_defaultChunkSizeBytes = 1024 * 64;
78+
private const int MaxDownloadRetries = 5;
79+
private readonly Func<TimeSpan> _retryDelayProvider;
7880

7981
private readonly ILogger _logger;
8082
private readonly IRegistryAPI _registryAPI;
@@ -87,7 +89,7 @@ internal sealed class Registry
8789
/// </summary>
8890
public string RegistryName { get; }
8991

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

@@ -96,15 +98,15 @@ internal Registry(string registryName, ILogger logger, RegistryMode mode, Regist
9698
{ }
9799

98100

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

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

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

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

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

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)