Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
996 views
in Technique[技术] by (71.8m points)

azure devops - Run only one instance of a build on VSTS

I have an agent queue in VSTS with several agents and I have a build assigned to this queue. Is there any way of telling VSTS that only one instance of the build should be run at a time, and the other instances (scheduled on other agents) should wait until the previous one finishes?

I need this because the tests create a temp database on which integration tests are run and if multiple instances are running against the same database then they interfere with each other.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

We implemented a custom VSTS task to do this. It works swimmingly. Here is the code.

If creating a custom VSTS task isn't your thing - you can strip out the PowerShell. Just have to pass the values as parameters instead.

file structure

/ Project-Folder
    - extension-icon.png
    - extension-manifest.json
    / Tasks
        / KeepBuildSynchronous
            - icon.png
            - task.json
            - task.ps1

extension-manifest.json

{
    "manifestVersion": 1,
    "id": "your-task-name",
    "name": "your-package-name",
    "version": "0.0.1",
    "publisher": "your-publisher-account",
    "targets": [
        {
            "id": "Microsoft.VisualStudio.Services"
        }
    ],    
    "description": "your-description",
    "categories": [
        "Build and release"
    ],
    "icons": {
        "default": "extension-icon.png"        
    },
    "files": [
        {
            "path": "Tasks/KeepBuildSynchronous"
        }
    ],
    "contributions": [
        {
            "id": "12345678-0000-0000-0000-000000000000", <-- must match task.json id
            "type": "ms.vss-distributed-task.task",
            "targets": [
                "ms.vss-distributed-task.tasks"
            ],
            "properties": {
                "name": "Tasks/KeepBuildSynchronous"
            }
        }
    ]
}

task.json

{
    "id": "12345678-0000-0000-0000-000000000000",
    "name": "keepBuildSynchronous",
    "friendlyName": "Keep Build Synchronous",
    "description": "Only allow one build with the same build definition to run at a time",
    "helpMarkDown": "",
    "category": "Utility",
    "visibility": [
        "Build"
    ],
    "runsOn": [
        "Agent",
        "DeploymentGroup"
    ],
    "author": "-your team-",
    "version": {
        "Major": 1,
        "Minor": 1,
        "Patch": 1
    },
    "releaseNotes": "Initial release",
    "minimumAgentVersion": "1.91.0",
    "inputs": [
        {
            "name": "waitTimeinMinutes",
            "type": "int",
            "label": "How many minutes do you want to wait before cancelling the build",
            "defaultValue": "15",
            "required": true,
            "helpMarkDown": ""
        }
    ],
    "instanceNameFormat": "Keep Build Synchronous",
    "execution": {
        "PowerShell3": {
            "target": "task.ps1"
        }
    }
}

task.ps1

[CmdletBinding()]
Param ()

Trace-VstsEnteringInvocation $MyInvocation
try {
    Import-VstsLocStrings "$PSScriptRootTask.json"

    # Get agent/build variables
    [string]$teamFoundationCollectionUri = Get-VstsTaskVariable -Name "system.teamFoundationCollectionUri"
    [string]$teamProjectId = Get-VstsTaskVariable -Name "system.teamProjectId"
    [string]$buildId = Get-VstsTaskVariable -Name "build.buildId"
    [int]$definitionId = Get-VstsTaskVariable -Name "system.definitionId" -AsInt
    [string]$accessToken = Get-VstsTaskVariable -Name "system.accessToken"

    # Get task inputs
    [int]$waitTimeinMinutes = Get-VstsInput -Name waitTimeinMinutes -AsInt

    [Object[]]$global:buildsByDefinition = $null
    [Object[]]$global:runningBuilds = $null

    function Get-Builds-By-Definition([int]$definitionId) {
        $url = "$teamFoundationCollectionUri/$teamProjectId/_apis/build/builds?api-version=2.0&definitions=$definitionId"

        $type = "application/json"
        $headers = @{
            Authorization = "Bearer $accessToken"
        }
        $global:buildsByDefinition = (Invoke-RestMethod -Uri $url -ContentType $type -Method Get -Headers $headers).value
        $global:runningBuilds = $buildsByDefinition | Where-Object -Property "status" -Value "inProgress" -EQ
    }

    [datetime]$startedAt = Get-Date
    [datetime]$waitUntil = $startedAt.AddMinutes($waitTimeinMinutes)

    Get-Builds-By-Definition -definitionId $definitionId

    [string]$buildDefinitionName = $buildsByDefinition[0].definition.name

    Write-Host ""
    Write-Host "Build definition ..... $buildDefinitionName"
    Write-Host "Current build ........ $buildId"
    Write-Host ""
    Write-Host "Started at ........... $startedAt"
    Write-Host "Willing to wait until  $waitUntil"
    Write-Host ""

    while (1 -eq 1) {

        if ((Get-Date) -gt $waitUntil) {
            Write-Host "Waited too long (cancelling)"
            throw "Waited longer than $waitTime minutes to start.  Cancelling."
        }

        if ($global:runningBuilds -eq $null) {
            Write-Host "No build running (weird, but ok...)"
            break
        }

        [int]$firstToGo = ($global:runningBuilds | Sort-Object -Property "Id")[0].Id

        if ($global:runningBuilds.Count -le 1 -or $buildId -le $firstToGo) {
            Write-Host "Your turn to shine"
            break
        } else {
            Write-Host "$($global:runningBuilds.Count) builds running. $firstToGo is next. (checking again)"
            Start-Sleep -Seconds 15
        }

        Get-Builds-By-Definition -definitionId $definitionId

    }
}
finally {
    Trace-VstsLeavingInvocation $MyInvocation
}

create the .vsix file

tfx extension create --manifest-globs extension-manifest.json --rev-version

I'll leave a little mystery and let you find out how to publish this to the marketplace and get it installed on your build agents


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...