Azure DevOps Server 2020 (オンプレミス) を使用しています。
根拠
私たちの PR ビルドはビルドに時間がかかります。msbuild/m:4
フラグを使用すると、クリーンからビルドするのに約 45 分かかります。パイプラインは、テストの目的で、ビルドの前に出力をクリーンアップして git clean を実行するように構成されています。
(実際の PR ビルドは出力を消去するだけで、リポジトリは消去しません)
maxCpuCount
msbuildパラメーターと、同じビルド サーバーで実行できる同時 PR ビルドの数 (つまり、ビルド エージェントの数)の最適な組み合わせを見つけようとしています。
誰も使用していない専用のビルド サーバーがあり、6 つのエージェントを構成しています。This is my Subject U nder Test . 次に、 REST API を使用して SUT でビルドをキューに入れる別のビルド サーバーでドライバー ビルドを実行します。
PR ビルドを任意の値でキューに入れることを知っていますmaxCpuCount
。問題は、同時ビルドをキューに入れる方法です。表面的には、同じ REST API を実行するだけで、SUT プールで次に使用可能なエージェントがそれを取得して実行します。ただし、ドライバー ビルドは進行状況の情報も出力します。実際には 1 つのビルドをキューに入れるわけではありませんが、前のビルドが完了するのを待っている間 (REST API を使用)、N ビルドを次々と実行します。失敗したビルドの後にクリーンアップして再起動するなど... ドライバー ビルド出力は、同じドライバー ビルドのトラブルシューティングに使用されます (これはコードであり、バグの対象となります)。
そのため、複数の Powershell ジョブ、PS 実行空間、またはスレッドを実行するオプションを削除しました。それらを組み合わせた出力を理解することは非常に問題になるからです。
代わりに、ドライバー ビルド自体の中で複数のジョブを定義することにしました。したがって、5 つのドライバー ビルド ジョブが同時に実行される場合、SUT 上で 5 つの PR ビルドを同時に実行していることになります。
最後に、そもそもなぜドライバーをビルドするのでしょうか? コンソールスクリプトを長時間実行しないのはなぜですか? いくつかの理由:
- デスクトップ マシンが夜間に頻繁に再起動される
- サーバー マシンは 15 分間、アクティビティがなくてもログアウトします。マウス ジガー ツールをインストールしたくありませんでした。許可されているかどうかわかりません。
- ドライバー コードを Windows サービスまたはスケジュールされたタスクとして配置しても、その進行状況を Azure DevOps と同じレベルで監視することはできません。
質問
私のテストには 2 つの側面があります。
- Max Degree of Parallelism または MaxDOP - msbuild
maxCpuCount
パラメーターにマップします - 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 ビルドは呼び出されません)。
小さなテスト マトリックスの使用: