1

我们使用 Azure DevOps Server 2020(本地)。

基本原理

我们的 PR 构建需要很长时间才能构建。使用 msbuild/m:4标志从干净构建大约需要 45 分钟。管道配置为清理输出并在构建之前运行 git clean 以用于我的测试

(实际的 PR 构建只清理输出,但不清理存储库)

我试图找出 msbuildmaxCpuCount参数和我们可以在同一构建服务器上运行的并发 PR 构建数量(即构建代理的数量)的最佳组合。

我有一个没有人使用的专用构建服务器,并在其上配置了 6 个代理。这是我的主题测试。接下来我有一个驱动程序构建在另一个构建服务器上运行,它使用 REST API 在 SUT 上对构建进行排队

我知道用任意maxCpuCount值排队 PR 构建。问题是 - 如何对并发构建进行排队?从表面上看 - 只需执行相同的 REST API,SUT 池中的下一个可用代理就会选择并运行它。但是,驱动程序构建也会输出一些进度信息。它实际上不会将一个构建排队,而是 N 一个接一个地构建,同时等待前一个构建完成(使用 REST API)。它会在构建失败后清理并重新启动它们,等等......驱动程序构建输出用于对相同的驱动程序构建进行故障排除(这是代码,因此会受到错误的影响)。

所以我放弃了运行多个 Powershell 作业或 PS 运行空间或线程的选项,因为理解它们的组合输出将是非常有问题的。

相反,我选择在驱动程序构建本身中定义多个作业。因此,如果同时运行 5 个驱动程序构建作业,这意味着我正在 SUT 上同时运行 5 个 PR 构建。

最后,为什么首先要构建驱动程序?为什么不长时间运行控制台脚本?几个原因:

  1. 我的台式机经常在晚上重启
  2. 服务器机器有 15 分钟无活动注销。我不想安装鼠标跳动工具 - 不确定我是否被允许。
  3. 将驱动程序代码安排为 Windows 服务或计划任务不能提供与 Azure DevOps 相同的便利级别来监控其进度。

问题

我的测试有两个维度:

  • Max Degree of Parallelism 或 MaxDOP - 映射到 msbuildmaxCpuCount参数
  • Agent Count - 参与测试的 SUT 构建代理的数量

由于我设计它的方式(如上所述),代理计数定义了驱动程序构建中同时运行的作业的数量。

我想实现以下测试矩阵:

MaxDOP X AgentCount = { 4,3,2,1 } X { 3, 4, 5, 6 }

例如,如果MaxDOP = 3 and AgentCount = 5,那么我将在 SUT 上将 5 个 PR 构建与/m:3. 总共有 6 个代理意味着这 5 个 PR 构建将同时运行。

我想为4 >= MaxDOP >= 1和的所有组合做到这一点3 <= AgentCount <= 6

所以我想出了以下驱动程序构建:

parameters:
  - name: ctx
    type: object
    default:
      - agentCount: 3
        maxDOP: 4
        dependsOn: Prepare
      - agentCount: 3
        maxDOP: 3
        dependsOn: MaxDOP_4x3_Agents
      - agentCount: 3
        maxDOP: 2
        dependsOn: MaxDOP_3x3_Agents
      - agentCount: 3
        maxDOP: 1
        dependsOn: MaxDOP_2x3_Agents
      - agentCount: 4
        maxDOP: 4
        dependsOn: MaxDOP_1x3_Agents
      - agentCount: 4
        maxDOP: 3
        dependsOn: MaxDOP_4x4_Agents
      - agentCount: 4
        maxDOP: 2
        dependsOn: MaxDOP_3x4_Agents
      - agentCount: 4
        maxDOP: 1
        dependsOn: MaxDOP_2x4_Agents
      - agentCount: 5
        maxDOP: 4
        dependsOn: MaxDOP_1x4_Agents
      - agentCount: 5
        maxDOP: 3
        dependsOn: MaxDOP_4x5_Agents
      - agentCount: 5
        maxDOP: 2
        dependsOn: MaxDOP_3x5_Agents
      - agentCount: 5
        maxDOP: 1
        dependsOn: MaxDOP_2x5_Agents
      - agentCount: 6
        maxDOP: 4
        dependsOn: MaxDOP_1x5_Agents
      - agentCount: 6
        maxDOP: 3
        dependsOn: MaxDOP_4x6_Agents
      - agentCount: 6
        maxDOP: 2
        dependsOn: MaxDOP_3x6_Agents
      - agentCount: 6
        maxDOP: 1
        dependsOn: MaxDOP_2x6_Agents

jobs:
 - job: Prepare
    steps:
      - Some preparation work

 - ${{ each ctx in parameters.ctx }}:
      - job: MaxDOP_${{ ctx.maxDOP }}x${{ ctx.agentCount }}_Agents
        variables:
          AgentCount: ${{ ctx.agentCount }}
        strategy:
          parallel: ${{ ctx.agentCount }}
        timeoutInMinutes: 60000
        dependsOn: ${{ ctx.dependsOn }}
        steps:
          - Queue the PR build on the SUT using ${{ ctx.maxDOP }} for maxCpuCount. The parallel strategy takes care to scale it ${{ ctx.agentCount }} times

 - job: Cleanup
    dependsOn:
      - MaxDOP_1x6_Agents
    condition: always()
    steps:
      - Some cleanup work

挑战在于同步作业。这是因为我不希望具有不同MaxDOP值的作业同时运行。例如,接受这份工作MaxDOP_3x4_Agents

  • 最大DOP = 3
  • 代理计数 = 4
  • 必须在 MaxDOP_4x4_Agents 之后运行

而且当然:

  • 第一个作业MaxDOP_4x3_Agents必须在Prepare作业之后运行
  • Cleanup作业必须在最后一个作业之后运行MaxDOP_1x6_Agents

如果不对所有 16 个测试矩阵单元进行明确编码,我就无法找到表达这种语义的方法。忽略dependsOn要求,2个嵌套for循环很容易完成这项工作:

parameters:
  - name: agentCounts
    type: object
    default: [3, 4, 5, 6]
  - name: maxDOPs
    type: object
    default: [4, 3, 2, 1]

...

  - ${{ each agentCount in parameters.agentCounts }}:
      - ${{ each maxDOP in parameters.maxDOPs }}:
          - job: MaxDOP_${{ maxDOP }}x${{ agentCount }}_Agents
            variables:
              AgentCount: ${{ agentCount }}
            strategy:
              parallel: ${{ agentCount }}
            timeoutInMinutes: 60000
            dependsOn: ????
            steps:
...

唉,我不知道如何在dependsOn这里指定。

驱动程序构建的一些快照(忽略持续时间,它目前是空运行,没有调用 SUT 上的实际 PR 构建): 在此处输入图像描述

在此处输入图像描述

使用一个小的测试矩阵:

在此处输入图像描述

4

0 回答 0