From 333b9d9ad453bc0e448fb1594bdbf3b4a7b3311f Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 18 Mar 2026 14:34:59 -0500 Subject: [PATCH 1/2] [xaprepare] Retry runtime pack restore up to 3 times The dotnet restore for runtime packs in Step_InstallDotNetPreview can time out (10-minute default) due to transient NuGet feed issues, causing the entire macOS build to fail and require manual reruns. Add retry logic (up to 3 attempts) so transient restore failures self-heal without manual intervention. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Steps/Step_InstallDotNetPreview.cs | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs index 1c0fb8e566e..717ca47c791 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs @@ -48,17 +48,29 @@ protected override async Task Execute (Context context) // Install runtime packs associated with the SDK previously installed. var packageDownloadProj = Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "build-tools", "xaprepare", "xaprepare", "package-download.proj"); var logPath = Path.Combine (Configurables.Paths.BuildBinDir, $"msbuild-{context.BuildTimeStamp}-download-runtime-packs.binlog"); - var runner = new ProcessRunner (Configurables.Paths.DotNetPreviewTool, "restore", - ProcessRunner.QuoteArgument (packageDownloadProj), - "--configfile", Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "NuGet.config"), - ProcessRunner.QuoteArgument ($"-bl:{logPath}"), - "--verbosity", "normal" - ) { - EchoStandardOutput = true, - EchoStandardError = true, - }; - if (!runner.Run ()) { - Log.ErrorLine ($"Failed to restore runtime packs using '{packageDownloadProj}'."); + + const int maxAttempts = 3; + bool restoreSucceeded = false; + for (int attempt = 1; attempt <= maxAttempts; attempt++) { + var runner = new ProcessRunner (Configurables.Paths.DotNetPreviewTool, "restore", + ProcessRunner.QuoteArgument (packageDownloadProj), + "--configfile", Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "NuGet.config"), + ProcessRunner.QuoteArgument ($"-bl:{logPath}"), + "--verbosity", "normal" + ) { + EchoStandardOutput = true, + EchoStandardError = true, + }; + if (runner.Run ()) { + restoreSucceeded = true; + break; + } + if (attempt < maxAttempts) { + Log.WarningLine ($"Failed to restore runtime packs (attempt {attempt}/{maxAttempts}), retrying..."); + } + } + if (!restoreSucceeded) { + Log.ErrorLine ($"Failed to restore runtime packs using '{packageDownloadProj}' after {maxAttempts} attempts."); return false; } From 8abf36435a1b4b2986d2cceffaebdf2087d5b632 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 19 Mar 2026 09:10:21 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs b/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs index 717ca47c791..01214519f05 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs @@ -47,11 +47,13 @@ protected override async Task Execute (Context context) // Install runtime packs associated with the SDK previously installed. var packageDownloadProj = Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "build-tools", "xaprepare", "xaprepare", "package-download.proj"); - var logPath = Path.Combine (Configurables.Paths.BuildBinDir, $"msbuild-{context.BuildTimeStamp}-download-runtime-packs.binlog"); + var logPathBase = Path.Combine (Configurables.Paths.BuildBinDir, $"msbuild-{context.BuildTimeStamp}-download-runtime-packs"); const int maxAttempts = 3; + const int initialBackoffDelayMilliseconds = 2000; bool restoreSucceeded = false; for (int attempt = 1; attempt <= maxAttempts; attempt++) { + var logPath = $"{logPathBase}-attempt{attempt}.binlog"; var runner = new ProcessRunner (Configurables.Paths.DotNetPreviewTool, "restore", ProcessRunner.QuoteArgument (packageDownloadProj), "--configfile", Path.Combine (BuildPaths.XamarinAndroidSourceRoot, "NuGet.config"), @@ -67,6 +69,8 @@ protected override async Task Execute (Context context) } if (attempt < maxAttempts) { Log.WarningLine ($"Failed to restore runtime packs (attempt {attempt}/{maxAttempts}), retrying..."); + var delayMilliseconds = initialBackoffDelayMilliseconds * (1 << (attempt - 1)); + await Task.Delay (delayMilliseconds); } } if (!restoreSucceeded) {