How Powershell slowed down the script to copy MediaCache from prod to stage slot
!!! Here is the link to the original article: link !!!.
The original script works fine, however, when the MediaCache folder grows, it takes longer and longer to execute and at some point it starts throwing timeouts every time. To me, it was weird because downloading MediaCache locally worked very fast every time, (it was 30 minutes vs 1 minute locally).
My colleague wrote an article How to expand archive with powershell where he compared performance between [io.compression.zipfile]::ExtractToDirectory
and Powershell’s Expand-Archive
command. The conclusion was that [io.compression.zipfile]::ExtractToDirectory
is much faster than the Powershell command.
I thought that maybe there is a similar situation with my script and it turned out that it is. Instead of using Invoke-RestMethod
I decided to use WebClient
and the results are amazing. The script finally works fast.
So I changed this:
Invoke-RestMethod -Uri $kuduApiUrl `
-Headers @{"Authorization"=$kuduApiAuthorisationToken;"If-Match"="*"} `
-Method GET `
-OutFile $localPath `
-ContentType "multipart/form-data"
To this:
$webClient = New-Object System.Net.WebClient
$webClient.Headers.Add("Authorization", $kuduApiAuthorisationToken)
$webClient.Headers.Add("If-Match", "*")
$webClient.Headers.Add("Content-Type","multipart/form-data");
$webClient.DownloadFile($kuduApiUrl, $localPath)
And here is the full script:
function Get-AzureRmWebAppPublishingCredentials($resourceGroupName, $webAppName, $slotName = $null){
if ([string]::IsNullOrWhiteSpace($slotName)){
$resourceType = "Microsoft.Web/sites/config"
$resourceName = "$webAppName/publishingcredentials"
}
else{
$resourceType = "Microsoft.Web/sites/slots/config"
$resourceName = "$webAppName/$slotName/publishingcredentials"
}
$publishingCredentials = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType $resourceType -ResourceName $resourceName -Action list -ApiVersion 2015-08-01 -Force
return $publishingCredentials
}
function Get-KuduApiAuthorisationHeaderValue($resourceGroupName, $webAppName, $slotName = $null){
$publishingCredentials = Get-AzureRmWebAppPublishingCredentials $resourceGroupName $webAppName $slotName
return ("Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $publishingCredentials.Properties.PublishingUserName, $publishingCredentials.Properties.PublishingPassword))))
}
function Get-ZippedMediaCacheFolderKuduApiUrl($webAppName, $slotName){
if ($slotName -eq $null)
{
return "https://$webAppName.scm.azurewebsites.net/api/zip/site/wwwroot/App_Data/MediaCache/"
}
return "https://$webAppName-$slotName.scm.azurewebsites.net/api/zip/site/wwwroot/App_Data/MediaCache/"
}
function Download-ZippedMediaCacheFolderFromWebApp($resourceGroupName, $webAppName, $localPath, $slotName = $null){
$kuduApiAuthorisationToken = Get-KuduApiAuthorisationHeaderValue $resourceGroupName $webAppName $slotName
$kuduApiUrl = Get-ZippedMediaCacheFolderKuduApiUrl $webAppName $slotName
Write-Host " Downloading MediaCache Folder. Source: '$kuduApiUrl'. Target: '$localPath'..." -ForegroundColor DarkGray
$webClient = New-Object System.Net.WebClient
$webClient.Headers.Add("Authorization", $kuduApiAuthorisationToken)
$webClient.Headers.Add("If-Match", "*")
$webClient.Headers.Add("Content-Type","multipart/form-data");
$webClient.DownloadFile($kuduApiUrl, $localPath)
}
$resourceGroupName = "$(ResourceGroupName)"
$webAppName = "$(WebAppName_CD)"
$localPath = "$(Agent.ReleaseDirectory)\MediaCache.zip"
Download-ZippedMediaCacheFolderFromWebApp $resourceGroupName $webAppName $localPath