Ich möchte nicht zulassen, dass zwei Jobs desselben Typs (dasselbe Repository) parallel auf demselben Knoten ausgeführt werden.
Wie kann ich das mit groovy in Jenkinsfile machen?
Antworten:
Die Antwort unter https://stackoverflow.com/a/43963315/6839445 ist veraltet.
Die aktuelle Methode zum Deaktivieren gleichzeitiger Builds besteht darin, folgende Optionen festzulegen:
options { disableConcurrentBuilds() }
Eine ausführliche Beschreibung finden Sie hier: https://jenkins.io/doc/book/pipeline/syntax/#options
Sie haben die Eigenschaft disableConcurrentBuilds erhalten:
properties properties: [
...
disableConcurrentBuilds(),
...
]
Dann würde der Job warten, bis der ältere fertig ist
Eine andere Möglichkeit ist die Verwendung des Plugins für abschließbare Ressourcen: https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin
Sie können Sperren (Mutexe) definieren, wie Sie möchten, und Variablen in die Namen einfügen. Um beispielsweise zu verhindern, dass mehrere Jobs gleichzeitig einen Compiler auf einem Build-Knoten verwenden:
stage('Build') {
lock(resource: "compiler_${env.NODE_NAME}", inversePrecedence: true) {
milestone 1
sh "fastlane build_release"
}
}
Wenn Sie also verhindern möchten, dass mehr als ein Job desselben Zweigs gleichzeitig pro Knoten ausgeführt wird, können Sie Folgendes 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/
inversePrecedence: true
beim Erstellen eines lock
?
Ich denke, es gibt mehr als nur einen Ansatz für dieses Problem.
lock
Schritt, wie in einer anderen Antwort vorgeschlagen.Execute concurrent builds if necessary
.node
oder label
für jedes Projekt ein.1
?Execute concurrent builds if necessary
von einem Jenkinsfile
?
Das " Throttle Concurrent Builds Plugin " unterstützt seitdem die Pipeline throttle-concurrents-2.0
. Jetzt können Sie so etwas tun:
Feuern Sie die Pipeline unten zweimal ab, unmittelbar nacheinander, und Sie werden sehen. Sie können dies manuell tun, indem Sie auf "Jetzt erstellen " doppelklicken oder es von einem parallel
Schritt in einem anderen Job aus aufrufen .
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:
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 erledige, 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 throttle
löst der Schritt das Problem nicht, da der throttle
Schritt derjenige innerhalb des node
Schritts ist und nicht umgekehrt. In diesem Fall ist der Sperrschritt besser für die Aufgabe geeignet
Installieren Sie das Jenkins Lockable Resources Plugin .
Wickeln Sie in Ihrem Pipeline-Skript das Teil in den Sperrblock und geben Sie dieser abschließbaren 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.
Wenn Sie wie mein Team sind, möchten Sie benutzerfreundlich parametrisierte Jenkins-Jobs haben, die Pipeline-Skripte schrittweise auslösen, anstatt all diese deklarative / groovige Suppe beizubehalten. Leider bedeutet dies, dass jeder Pipeline-Build 2+ Executor-Slots belegt (einer 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()
nur verhindert , dass derselbe Job (Zweig) zweimal ausgeführt wird. Es werden keine Pipeline-Builds für verschiedene Zweige in die Warteschlange gestellt und gewartet, anstatt wertvolle Executor-Slots zu belegen.
Eine hackige (aber überraschend elegante) Lösung für uns bestand darin, die Executoren des Masterknotens auf 1 zu beschränken und die Pipeline-Skripte dazu zu bringen, sie (und nur sie) zu verwenden, und dann einen lokalen Slave-Agenten an Jenkins anzuschließen, um sich um alle zu kümmern andere Beschäftigungen.
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, das Jenkins nach Informationen zu aktuellen Jobs abfragt und prüfen, ob Jobs des gleichen Typs ausgeführt werden. Verwenden Sie dazu die Jenkins REST-API. Die Dokumentation finden Sie 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 jede Sprache verwenden. Rufen Sie dann 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 warten (nicht zu verwechseln mit Erwähnungen von Integrationstests, es ist nur der Jobname).
Beachten Sie auch, dass dieses Skript in seltenen Fällen zu einem Deadlock führen kann, wenn beide Jobs aufeinander warten. Daher möchten Sie hier möglicherweise einige Richtlinien für maximale Wiederholungsversuche implementieren, anstatt unendlich lange zu warten.
Bis das Plugin "Throttle Concurrent Builds" Pipeline-Unterstützung bietet, besteht eine Lösung darin, einen Executor des Masters mit einem für Ihren Job erforderlichen Label effektiv auszuführen.
Erstellen Sie dazu in Jenkins einen neuen Knoten, z. B. einen SSH-Knoten, der eine Verbindung zu localhost herstellt. Sie können auch die Befehlsoption verwenden, um Slave.jar / swarm.jar abhängig von Ihrem Setup auszuführen. Geben Sie dem Knoten einen Executor und ein Label wie "resource-foo" und geben Sie Ihrem Job auch dieses Label. Jetzt kann jeweils nur ein Job des Labels "resource-foo" ausgeführt werden, da nur ein Executor mit dieser Beschriftung vorhanden ist. Wenn Sie festlegen, dass der Knoten so oft wie möglich verwendet wird (Standard) und die Anzahl der Master-Executoren um eins reduzieren, sollte er sich genau wie gewünscht verhalten, ohne die Gesamtzahl der Executoren zu ändern.