diff --git a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp index aa876a2147..f15d120b60 100644 --- a/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/DownloadFlow.cpp @@ -307,7 +307,8 @@ namespace AppInstaller::CLI::Workflow std::optional> hash; - const int MaxRetryCount = 2; + constexpr int MaxRetryCount = 2; + constexpr std::chrono::seconds maximumWaitTimeAllowed = 60s; for (int retryCount = 0; retryCount < MaxRetryCount; ++retryCount) { bool success = false; @@ -323,6 +324,27 @@ namespace AppInstaller::CLI::Workflow success = true; } + catch (const ServiceUnavailableException& sue) + { + if (retryCount < MaxRetryCount - 1) + { + auto waitSecondsForRetry = sue.RetryAfter(); + if (waitSecondsForRetry > maximumWaitTimeAllowed) + { + throw; + } + + bool waitCompleted = context.Reporter.ExecuteWithProgress([&waitSecondsForRetry](IProgressCallback& progress) + { + return ProgressCallback::Wait(progress, waitSecondsForRetry); + }); + + if (!waitCompleted) + { + break; + } + } + } catch (...) { if (retryCount < MaxRetryCount - 1) diff --git a/src/AppInstallerCLITests/TestCommon.cpp b/src/AppInstallerCLITests/TestCommon.cpp index 72ae57368d..a418aefe85 100644 --- a/src/AppInstallerCLITests/TestCommon.cpp +++ b/src/AppInstallerCLITests/TestCommon.cpp @@ -186,11 +186,6 @@ namespace TestCommon return {}; } - bool TestProgress::Wait(std::chrono::milliseconds) - { - return false; - } - wil::unique_hkey RegCreateVolatileTestRoot() { // First create/open the real test root diff --git a/src/AppInstallerCLITests/TestCommon.h b/src/AppInstallerCLITests/TestCommon.h index 10b28be761..cb21b76aed 100644 --- a/src/AppInstallerCLITests/TestCommon.h +++ b/src/AppInstallerCLITests/TestCommon.h @@ -109,8 +109,6 @@ namespace TestCommon CancelFunctionRemoval SetCancellationFunction(std::function&& f) override; - bool Wait(std::chrono::milliseconds millisecondsToWait) override; - std::function m_OnProgress; }; diff --git a/src/AppInstallerCommonCore/Downloader.cpp b/src/AppInstallerCommonCore/Downloader.cpp index 040dc27360..1fc0fcceea 100644 --- a/src/AppInstallerCommonCore/Downloader.cpp +++ b/src/AppInstallerCommonCore/Downloader.cpp @@ -514,8 +514,7 @@ namespace AppInstaller::Utility { if (hre.code() == APPINSTALLER_CLI_ERROR_SERVICE_UNAVAILABLE) { - auto retryAfter = httpRandomAccessStream->RetryAfter(); - THROW_EXCEPTION(AppInstaller::Utility::ServiceUnavailableException(retryAfter)); + THROW_EXCEPTION(AppInstaller::Utility::ServiceUnavailableException(httpRandomAccessStream->RetryAfter())); } throw; diff --git a/src/AppInstallerCommonCore/MsixInfo.cpp b/src/AppInstallerCommonCore/MsixInfo.cpp index 04ef88f2ff..c27d606136 100644 --- a/src/AppInstallerCommonCore/MsixInfo.cpp +++ b/src/AppInstallerCommonCore/MsixInfo.cpp @@ -532,7 +532,6 @@ namespace AppInstaller::Msix { m_stream = Utility::GetReadOnlyStreamFromURI(uriStr); - // Here if thrown APPINSTALLER_CLI_ERROR_SERVICE_UNAVAILABLE somehow get RetryAfter if (GetBundleReader(m_stream.Get(), &m_bundleReader)) { m_isBundle = true; diff --git a/src/AppInstallerCommonCore/Progress.cpp b/src/AppInstallerCommonCore/Progress.cpp index 5c98a2f033..4288256507 100644 --- a/src/AppInstallerCommonCore/Progress.cpp +++ b/src/AppInstallerCommonCore/Progress.cpp @@ -64,12 +64,12 @@ namespace AppInstaller } } - bool ProgressCallback::Wait(std::chrono::milliseconds millisecondsToWait) + bool ProgressCallback::Wait(IProgressCallback& progress, std::chrono::milliseconds millisecondsToWait) { wil::unique_event calledEvent; calledEvent.create(); - auto cancellationFunc = this->SetCancellationFunction([&calledEvent]() + auto cancellationFunc = progress.SetCancellationFunction([&calledEvent]() { calledEvent.SetEvent(); }); diff --git a/src/AppInstallerCommonCore/Public/AppInstallerProgress.h b/src/AppInstallerCommonCore/Public/AppInstallerProgress.h index 420ce4b4f8..9ba643dc34 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerProgress.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerProgress.h @@ -70,9 +70,6 @@ namespace AppInstaller // Sets a cancellation function that will be called when the operation is to be cancelled. [[nodiscard]] virtual CancelFunctionRemoval SetCancellationFunction(std::function&& f) = 0; - - // Waits with cancellation. Returns false if cancelled before timeout. - virtual bool Wait(std::chrono::milliseconds millisecondsToWait) = 0; }; // Implementation of IProgressCallback. @@ -81,6 +78,8 @@ namespace AppInstaller ProgressCallback() = default; ProgressCallback(IProgressSink* sink); + static bool Wait(IProgressCallback& progress, std::chrono::milliseconds ms); + void BeginProgress() override; void OnProgress(uint64_t current, uint64_t maximum, ProgressType type) override; @@ -93,8 +92,6 @@ namespace AppInstaller [[nodiscard]] IProgressCallback::CancelFunctionRemoval SetCancellationFunction(std::function&& f) override; - bool Wait(std::chrono::milliseconds ms) override; - void Cancel(CancelReason reason = CancelReason::Abort); IProgressSink* GetSink(); diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp index f79a708eb6..b8c6b4dcbe 100644 --- a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp +++ b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp @@ -142,7 +142,8 @@ namespace AppInstaller::Repository::Microsoft AICLI_LOG(Repo, Info, << "Downloading manifest"); ProgressCallback emptyCallback; - const int MaxRetryCount = 2; + constexpr int MaxRetryCount = 2; + constexpr std::chrono::seconds maximumWaitTimeAllowed = 10s; for (int retryCount = 0; retryCount < MaxRetryCount; ++retryCount) { try @@ -157,6 +158,25 @@ namespace AppInstaller::Repository::Microsoft break; } + catch (const ServiceUnavailableException& sue) + { + if (retryCount < MaxRetryCount - 1) + { + auto waitSecondsForRetry = sue.RetryAfter(); + if (waitSecondsForRetry > maximumWaitTimeAllowed) + { + throw; + } + + // TODO: Get real progress callback to allow cancelation. + auto ms = std::chrono::duration_cast(waitSecondsForRetry); + Sleep(static_cast(ms.count())); + } + else + { + throw; + } + } catch (...) { if (retryCount < MaxRetryCount - 1) diff --git a/src/AppInstallerRepositoryCore/RepositorySource.cpp b/src/AppInstallerRepositoryCore/RepositorySource.cpp index cf9c6edb82..de06ccbafd 100644 --- a/src/AppInstallerRepositoryCore/RepositorySource.cpp +++ b/src/AppInstallerRepositoryCore/RepositorySource.cpp @@ -66,13 +66,6 @@ namespace AppInstaller::Repository { AddOrUpdateResult result; - // Do not update if we are still before the update block time. - if (IsUpdateSuppressed(details)) - { - AICLI_LOG(Repo, Info, << "Update is suppressed until: " << details.DoNotUpdateBefore); - return {}; - } - auto factory = ISourceFactory::GetForType(details.Type); // If we are instructed to wait longer than this, just fail rather than retrying. @@ -109,7 +102,7 @@ namespace AppInstaller::Repository AICLI_LOG(Repo, Info, << "Source add/update failed, waiting " << millisecondsToWait.count() << " milliseconds and retrying: " << details.Name); - if (!progress.Wait(millisecondsToWait)) + if (!ProgressCallback::Wait(progress, millisecondsToWait)) { AICLI_LOG(Repo, Info, << "Source second try cancelled."); return {}; diff --git a/src/WinGetUtil/pch.h b/src/WinGetUtil/pch.h index 0de0f60cd9..99d149eb3a 100644 --- a/src/WinGetUtil/pch.h +++ b/src/WinGetUtil/pch.h @@ -17,3 +17,5 @@ #include #include #include + +#include