wake-up-neo.com

Wie kann ich verhindern, dass zwei Pipeline-Jenkins-Jobs desselben Typs auf demselben Knoten parallel ausgeführt werden?

Ich möchte nicht zulassen, dass zwei Jobs desselben Typs (dasselbe Repository) nicht auf demselben Knoten parallel ausgeführt werden.

Wie kann ich dies tun, wenn ich in Jenkinsfile groovig bin?

39
sorin

Sie haben die Eigenschaft disableConcurrentBuilds erhalten:

properties properties: [
  ...
  disableConcurrentBuilds(),
  ...
]

Dann würde der Job warten, bis der ältere fertig ist

34
hypery2k

Die Antwort in https://stackoverflow.com/a/43963315/6839445 ist veraltet.

Die aktuelle Methode zum Deaktivieren gleichzeitiger Builds besteht im Festlegen von Optionen:

options { disableConcurrentBuilds() }

Eine ausführliche Beschreibung finden Sie hier: https://jenkins.io/doc/book/pipeline/syntax/#options

21
M0nt3c1t0

Eine andere Möglichkeit ist die Verwendung des Plugins für Sperrbare Ressourcen: https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin

Sie können Sperren (Mutexe) beliebig definieren und Variablen in die Namen einfügen. Z.B. So verhindern Sie, dass mehrere Jobs einen Compiler gleichzeitig auf einem Buildknoten verwenden:

stage('Build') {
    lock(resource: "compiler_${env.NODE_NAME}", inversePrecedence: true) {
      milestone 1
      sh "fastlane build_release"
    }
}

Wenn Sie also verhindern möchten, dass mehrere Jobs desselben Zweigs gleichzeitig pro Knoten ausgeführt werden, können Sie so etwas tun

stage('Build') {
    lock(resource: "lock_${env.NODE_NAME}_${env.BRANCH_NAME}", inversePrecedence: true) {
      milestone 1
      sh "fastlane build_release"
    }
}

Von: https://www.quernus.co.uk/2016/10/19/lockable-resources-jenkins-pipeline-builds/

19
Matt Hamilton

Ich denke, es gibt mehr als nur einen Ansatz für dieses Problem.

Pipeline

  • Verwenden Sie die neueste Version des Lockable Resources Plugin und dessen lock-Schritt, wie in der anderen Antwort vorgeschlagen. 
  • Wenn Sie dasselbe Projekt erstellen:
    • Deaktivieren Sie Execute concurrent builds if necessary.
  • Wenn Sie andere Projekte erstellen:
    • Legen Sie für jedes Projekt eine andere node oder label fest.

Jenkins

  • Anzahl der Executoren des Knotens auf 1 beschränken?

Plugins

12
luka5z

Das " Throttle Concurrent Builds Plugin " unterstützt nun Pipeline seit throttle-concurrents-2.0. Jetzt kannst du so etwas tun:

// Fire me twice, one immediately after the other
// by double-clicking 'Build Now' or from a parallel step in another job.
stage('pre'){
    echo "I can run in parallel"
    sleep(time: 10, unit:'SECONDS')
}
throttle(['my-throttle-category']) {

    // Because only the node block is really throttled.
    echo "I can also run in parallel" 

    node('some-node-label') {

        echo "I can only run alone"

        stage('work') {

            echo "I also can only run alone"
            sleep(time: 10, unit:'SECONDS')

        }
    }
}
stage('post') {
    echo "I can run in parallel again"
    // Let's wait enough for the next execution to catch
    // up, just to illustrate.
    sleep(time: 20, unit:'SECONDS')
}

In der Pipeline-Ansicht können Sie Folgendes erkennen:

 enter image description here

Bitte beachten Sie jedoch, dass dies nur für node-Blöcke innerhalb des throttle-Blocks funktioniert. Ich habe andere Pipelines, in denen ich zuerst einen Knoten zuweise, dann einige Arbeiten mache, die nicht gedrosselt werden müssen, und dann einige, die dies tun. 

node('some-node-label') {

    //do some concurrent work

    //This WILL NOT work.
    throttle(['my-throttle-category']) {
        //do some non-concurrent work
    }
}

In diesem Fall löst der Schritt throttle das Problem nicht, da der Schritt throttle der Schritt innerhalb des Schrittes node ist und nicht umgekehrt. In diesem Fall ist der Sperrschritt besser für die Aufgabe geeignet

9
Mig82

Beispiel für den Einsatz eines Optionsblocks in der deklarativen Pipelinesyntax:

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}
8
Bryji

Installieren Sie Jenkins Lockable Resources Plugin .

Wickeln Sie in Ihrem Pipeline-Skript das Teil in den Sperrblock und geben Sie dieser verriegelbaren Ressource einen Namen.

lock("test-server"){
    // your steps here
}

Verwenden Sie den Namen der Ressource, die Sie sperren. Nach meiner Erfahrung ist es normalerweise ein Testserver oder eine Testdatenbank.

5
raitisd

Eine der Optionen ist die Verwendung der Jenkins REST - API. Ich habe nach anderen Optionen gesucht, aber es scheint, dass dies nur eine mit Pipelines-Funktionalität ist.

Sie sollten ein Skript schreiben, in dem Jenkins nach Informationen zu den aktuell ausgeführten Jobs gefragt wird, und prüfen, ob ein Job desselben Typs ausgeführt wird. Dazu sollten Sie die API von Jenkins REST verwenden. Die Dokumentation finden Sie möglicherweise in der rechten unteren Ecke Ihrer Jenkins-Seite . Beispielskript:

#!/usr/bin/env bash

# this script waits for integration test build finish
# usage: ./wait-for-tests.sh <jenkins_user_id> <jenkins_user_token_id>
jenkins_user=$1
jenkins_token=$2
build_number=$3

job_name="integration-tests"
branch="develop"

previous_build_number=build_number
let previous_build_number-=1
previous_job_status=$(curl -s http://${jenkins_user}:${jenkins_token}@jenkins.mycompany.com/job/mycompany/job/${job_name}/branch/${branch}/${previous_build_number}/api/json | jq -r '.result')

while [ "$previous_job_status" == "null" ];
do
    previous_job_status=$(curl -s http://${jenkins_user}:${jenkins_token}@jenkins.mycompany.com/job/mycompany/job/${job_name}/branch/${branch}/${previous_build_number}/api/json | jq -r '.result')
    echo "Waiting for tests completion"
    sleep 10
done

echo "Seems that tests are finished."

Ich habe hier bash verwendet, aber Sie können eine beliebige Sprache verwenden .. Dann rufen Sie einfach dieses Skript in Ihrer Jenkins-Datei auf:

sh "./wait-for-tests.sh ${env.REMOTE_USER} ${env.REMOTE_TOKEN} ${env.BUILD_NUMBER}"

Es wird also bis zum Abschluss des Jobs gewartet (nicht mit den Erwähnungen des Integrationstests verwechseln, es handelt sich lediglich um den Jobnamen). 

Beachten Sie auch, dass dieses Skript in seltenen Fällen zu einem Deadlock führen kann, wenn beide Jobs auf einander warten. Daher möchten Sie hier möglicherweise einige Richtlinien für die maximale Anzahl von Wiederholungen anstelle des endlosen Wartens anwenden.

2

Bis das Plugin "Throttle Concurrent Builds" Pipeline-Unterstützung hat, besteht die Lösung darin, einen Executor des Masters effektiv mit einem Label auszuführen, das für Ihren Job erforderlich ist.

Erstellen Sie dazu in Jenkins einen neuen Knoten, z. B. einen SSH-Knoten, der eine Verbindung zu localhost herstellt. Sie können die Befehlsoption auch zum Ausführen von slave.jar/swarm.jar verwenden, abhängig von Ihrem Setup. Geben Sie dem Knoten einen Executor und ein Label wie "resource-foo", und geben Sie Ihrem Job dieses Label. Jetzt kann immer nur ein Job des Labels "resource-foo" gleichzeitig ausgeführt werden, da es nur einen Executor mit diesem Label gibt. Wenn Sie den Knoten so einstellen, dass er so weit wie möglich verwendet wird (Standardeinstellung) und die Anzahl der Master-Executoren um eins reduzieren, sollte er sich genau wie gewünscht verhalten, ohne die Gesamt-Executoren zu ändern.

1
mrooney

Wenn Sie wie mein Team sind, möchten Sie benutzerfreundlich parametrisierte Jenkins-Jobs, die Pipeline-Skripts stufenweise auslösen, anstatt all diese deklarativen/groovigen Suppen zu verwenden. Leider bedeutet dies, dass jeder Pipeline-Build mehr als 2 Executor-Slots beansprucht (einen für das Pipeline-Skript und andere für die ausgelösten Jobs), sodass die Gefahr eines Deadlocks sehr real wird. 

Ich habe überall nach Lösungen für dieses Dilemma gesucht und disableConcurrentBuilds () verhindert nur, dass derselbe Job (Zweig) zweimal ausgeführt wird. Es werden keine Pipeline-Builds für verschiedene Zweige erstellt, die warten, anstatt wertvolle Executor-Slots in Anspruch zu nehmen.

Eine hackige (aber überraschend elegante) Lösung für uns bestand darin, die Executoren des Master-Knotens auf 1 zu beschränken und die Pipeline-Scripts dazu zu bringen, sie (und nur sie) zu verwenden, und dann einen lokalen Slave-Agenten an Jenkins anschließen, um sich um alles zu kümmern andere Beschäftigungen.

0
JohannSig