You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure DevOps Server中downloadbuildartifacts@0下载过慢或失败问题求助

Azure DevOps Server构件下载过慢/超时问题求助

背景

我们正在使用Azure DevOps Server,遇到了构件下载过慢或60分钟超时的问题。
在DeploymentJob中添加downloadbuildartifacts@0任务时,即便构件大小仅为200KB也会出现该问题。

服务器性能表现

  • Server A、B、C三台服务器下载同一构件分别耗时4分钟、6分钟,其中Server C出现60分钟超时。
  • 三台服务器均配置了NETWORK SERVICE账户。

已尝试的解决方法(均无效)

  • 尝试使用downloadbuildartifacts@1任务,但无法找到该任务。
  • 尝试downloadpipelineartifact@2任务,但该任务不适用于Azure DevOps Server。
  • 通过浏览器使用API链接手动下载,速度正常(耗时不到2秒),排除网络问题。

手动下载的API链接:

http://{{server}}/DefaultCollection/_apis/resources/Containers/{{BuildID}}?itemPath={{ArtifactName}}&isShallow=true&api-version=4.1-preview.4

临时解决方案

1. 使用PowerShell自定义下载任务

我们采用PowerShell编写了自定义下载任务,耗时约40秒。

steps:
  - powershell: |
      function Get-ContentRecursively {
          param (
              [string]$Url,
              [hashtable]$Headers,
              [string]$FilenameFilterPattern
          )

          try {
              if ( $null -eq ($AccessUrl | Where-Object { $_ -eq $Url })){
                $content = Invoke-WebRequest -Uri $Url -Headers $Headers -UseBasicParsing -TimeoutSec 60
                Write-Host "[$($content.StatusCode)] $($content.StatusDescription) - Accessed $Url"
                $global:accessUrl += $Url
              }
              else {
                return
              }
          } catch {
              Write-Host "Error accessing ${Url}: $_"
              return
          }

          try {
              $json = $content.Content | ConvertFrom-Json
          } catch {
              Write-Host "Failed to parse JSON from $Url"
              return
          }

          foreach ($item in $json.value) {
              if ($item.itemType -eq "folder") {
                  Get-ContentRecursively -Url $item.contentLocation -Headers $Headers -FilenameFilterPattern $FilenameFilterPattern
              } elseif ($item.itemType -eq "file") {
                  $file = $global:files | Where-Object { $_.path -eq $item.path }
                  
                  # add if file not exists
                  if( $file -eq $null ){
                      $global:files += $item
                      Write-Host "Add $($item.path) to FileList"
                  }
              }
          }
      }

      function Download-File {
          param (
              [object]$File,
              [hashtable]$Headers,
              [string]$OutFilePath,
              [int]$RetryCount = 4
          )

          $retryAttempts = 0
          do {
              try {
                  $tempPath = Join-Path $OutFilePath $File.path
                  
                  $directory = Split-Path $tempPath  
                  if (-not (Test-Path $directory)) {
                      New-Item -ItemType Directory -Force -Path $directory > $null
                  }
              
                  $response = Invoke-WebRequest -Uri $File.contentLocation -Headers $headers -UseBasicParsing -OutFile $tempPath  -TimeoutSec 60 -PassThru
                  
                  Write-Host "[$($response.StatusCode)] $($response.StatusDescription) - Downloaded $($File.contentLocation)"
                  Write-Host "Downloaded $($File.contentLocation) to $tempPath"
                  return
              } catch {
                  $retryAttempts++
                  Write-Host "[$($response.StatusCode)] $($response.StatusDescription) - Downloaded $($File.contentLocation)"
                  Write-Host "Attempt $retryAttempts of $RetryCount for $Url failed. Error: $_"
                  Start-Sleep -Seconds (2 * $retryAttempts)
              }
          } while ($retryAttempts -lt $RetryCount)
          Write-Host "Failed to download: $($File.contentLocation) after $RetryCount retries."
          $global:failDownload += $File.contentLocation
      }

      # Main logic
      $token = "$(System.AccessToken)"
      $organization = "$(System.TeamFoundationCollectionUri)"
      $project = "$(System.TeamProject)"
      $headers = @{Authorization = "Bearer $token"}
      $initialUrl = $env:SYSTEM_TASKDEFINITIONSURI + '/_apis/resources/Containers/' + $env:BUILD_CONTAINERID
      $outFilePath = $env:SYSTEM_ARTIFACTSDIRECTORY

      $filenameFilterPattern = "*" # Example pattern
      $global:files = @()
      $global:failDownload = @()
      $global:accessUrl = @()

      Get-ContentRecursively -Url $initialUrl -Headers $headers -FilenameFilterPattern $filenameFilterPattern
      
      Write-Host "Prepare to download"
      
      foreach ($file in $global:files) {
        Download-File -File $file -Headers $headers -OutFilePath $outFilePath
      }
      if ( $global:failDownload.Length -ne 0 ){
        exit 1
      }
    displayName: myDownloadTask

2. 使用经典发布流水线下载

通过经典发布流水线下载耗时仅5秒,但无法使用YAML进行部署。

寻求解决方案

请问是否有人遇到过类似问题并找到了解决方案?


内容的提问来源于stack exchange,提问作者littletree71

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:16:00