diff --git a/.github/workflows/scripts/windows/install-vsb.ps1 b/.github/workflows/scripts/windows/install-vsb.ps1 index 931cbbb..cdd3ed0 100644 --- a/.github/workflows/scripts/windows/install-vsb.ps1 +++ b/.github/workflows/scripts/windows/install-vsb.ps1 @@ -9,13 +9,20 @@ ## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## + +Import-Module $PSScriptRoot\web-request-utils.psm1 + $VSB='https://download.visualstudio.microsoft.com/download/pr/5536698c-711c-4834-876f-2817d31a2ef2/c792bdb0fd46155de19955269cac85d52c4c63c23db2cf43d96b9390146f9390/vs_BuildTools.exe' $VSB_SHA256='C792BDB0FD46155DE19955269CAC85D52C4C63C23DB2CF43D96B9390146F9390' Set-Variable ErrorActionPreference Stop Set-Variable ProgressPreference SilentlyContinue Write-Host -NoNewLine ('Downloading {0} ... ' -f ${VSB}) -Invoke-WebRequest -Uri $VSB -OutFile $env:TEMP\vs_buildtools.exe -Write-Host 'SUCCESS' +try { + Invoke-WebRequestWithRetry -Uri $VSB -OutFile $env:TEMP\vs_buildtools.exe +} +catch { + exit 1 +} Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $VSB_SHA256) $Hash = Get-FileHash $env:TEMP\vs_buildtools.exe -Algorithm sha256 if ($Hash.Hash -eq $VSB_SHA256) { diff --git a/.github/workflows/scripts/windows/swift/install-swift.ps1 b/.github/workflows/scripts/windows/swift/install-swift.ps1 index 811a53d..901aa17 100644 --- a/.github/workflows/scripts/windows/swift/install-swift.ps1 +++ b/.github/workflows/scripts/windows/swift/install-swift.ps1 @@ -9,6 +9,9 @@ ## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## + +Import-Module $PSScriptRoot\..\web-request-utils.psm1 + function Install-Swift { param ( [string]$Url, @@ -17,8 +20,12 @@ function Install-Swift { Set-Variable ErrorActionPreference Stop Set-Variable ProgressPreference SilentlyContinue Write-Host -NoNewLine ('Downloading {0} ... ' -f $url) - Invoke-WebRequest -Uri $url -OutFile installer.exe - Write-Host 'SUCCESS' + try { + Invoke-WebRequestWithRetry -Uri $url -OutFile installer.exe + } + catch { + exit 1 + } Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $Sha256) $Hash = Get-FileHash installer.exe -Algorithm sha256 if ($Hash.Hash -eq $Sha256 -or $Sha256 -eq "") { diff --git a/.github/workflows/scripts/windows/web-request-utils.psm1 b/.github/workflows/scripts/windows/web-request-utils.psm1 new file mode 100644 index 0000000..7e3f49b --- /dev/null +++ b/.github/workflows/scripts/windows/web-request-utils.psm1 @@ -0,0 +1,75 @@ +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift.org open source project +## +## Copyright (c) 2024 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +## +##===----------------------------------------------------------------------===## + +# Shared utilities for web requests with retry logic + +<# +.SYNOPSIS +Invokes a web request with retry logic and exponential backoff. + +.DESCRIPTION +Attempts to download a file from a URL with automatic retry on failure. +Uses exponential backoff to handle transient network failures. + +.PARAMETER Uri +The URL to download from. + +.PARAMETER OutFile +The destination file path for the download. + +.PARAMETER MaxRetries +Maximum number of retry attempts (default: 10). + +.PARAMETER BaseDelay +Base delay in seconds for exponential backoff (default: 1). + +.EXAMPLE +Invoke-WebRequestWithRetry -Uri "https://example.com/file.exe" -OutFile "file.exe" + +.EXAMPLE +Invoke-WebRequestWithRetry -Uri "https://example.com/file.exe" -OutFile "file.exe" -MaxRetries 5 -BaseDelay 2 +#> +function Invoke-WebRequestWithRetry { + param( + [Parameter(Mandatory=$true)] + [string]$Uri, + [Parameter(Mandatory=$true)] + [string]$OutFile, + [int]$MaxRetries = 10, + [int]$BaseDelay = 1 + ) + + $Attempt = 0 + $Success = $false + + while (-not $Success -and $Attempt -lt $MaxRetries) { + $Attempt++ + try { + Invoke-WebRequest -Uri $Uri -OutFile $OutFile + $Success = $true + Write-Host 'SUCCESS' + } + catch { + if ($Attempt -eq $MaxRetries) { + Write-Host "FAILED after $MaxRetries attempts: $($_.Exception.Message)" + throw + } + + # Calculate exponential backoff delay (2^attempt * base delay) + $Delay = $BaseDelay * [Math]::Pow(2, $Attempt - 1) + Write-Host "Attempt $Attempt failed, retrying in $Delay seconds..." + Start-Sleep -Seconds $Delay + } + } +} + +Export-ModuleMember -Function Invoke-WebRequestWithRetry