web-dev-qa-db-fra.com

Comment empêcher deux travaux jenkins de pipeline du même type de s'exécuter en parallèle sur le même noeud?

Je souhaite ne pas autoriser deux tâches du même type (même référentiel) à s'exécuter en parallèle sur le même nœud.

Comment puis-je faire cela en utilisant groovy dans Jenkinsfile?

39
sorin

Vous avez la propriété disableConcurrentBuilds:

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

Ensuite, le travail attendrait le plus âgé pour finir en premier

34
hypery2k

La réponse fournie dans (https://stackoverflow.com/a/43963315/6839445 } _ est obsolète.

La méthode actuelle pour désactiver les versions simultanées consiste à définir des options:

options { disableConcurrentBuilds() }

Une description détaillée est disponible ici: https://jenkins.io/doc/book/pipeline/syntax/#options }

21
M0nt3c1t0

Une autre méthode consiste à utiliser le plugin Lockable Resources: https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin

Vous pouvez définir les verrous (mutex) comme vous le souhaitez et mettre des variables dans les noms. Par exemple. pour empêcher plusieurs travaux d'utiliser simultanément un compilateur sur un noeud de construction:

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

Donc, si vous voulez empêcher plus d'un travail de la même branche de s'exécuter simultanément par nœud, vous pouvez faire quelque chose comme:

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

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

19
Matt Hamilton

Je pense qu'il y a plus d'une approche à ce problème.

Pipeline

  • Utilisez la dernière version de Lockable Resources Plugin et son étape lock, comme suggéré dans une autre réponse. 
  • Si vous construisez le même projet:
    • Désélectionnez Execute concurrent builds if necessary.
  • Si vous construisez différents projets:
    • Définissez différents node ou label pour chaque projet.

Jenkins

  • Limiter le nombre d'exécuteurs du noeud à 1?

Plug-ins

12
luka5z

Le plug-in " Throttle Concurrent Builds " prend désormais en charge le pipeline depuis throttle-concurrents-2.0. Alors maintenant, vous pouvez faire quelque chose comme ça:

// 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')
}

Dans la vue de l'étape du pipeline, vous pourrez apprécier ceci:

 enter image description here

Cependant, veuillez noter que cela ne fonctionne que pour les blocs node au sein du bloc throttle. J'ai d'autres pipelines dans lesquels je commence par allouer un nœud, puis je fais un travail qui ne nécessite pas de limitation et d'autres qui le font. 

node('some-node-label') {

    //do some concurrent work

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

Dans ce cas, l'étape throttle ne résout pas le problème car l'étape throttle est celle qui se trouve à l'intérieur de l'étape node et non l'inverse. Dans ce cas l'étape de verrouillage convient mieux à la tâche

9
Mig82

Exemple d'utilisation d'un bloc d'options dans la syntaxe déclarative du pipeline:

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}
8
Bryji

Installez Jenkins Lockable Resources Plugin .

Dans votre script de pipeline, placez la pièce dans le bloc de verrouillage et attribuez un nom à cette ressource verrouillable.

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

Utilisez le nom de la ressource que vous verrouillez. D'après mon expérience, il s'agit généralement d'un serveur de test ou d'une base de données de test.

5
raitisd

Une des options consiste à utiliser l'API Jenkins REST. J'ai recherché d'autres options, mais il semble que ce ne soit qu'une option disponible avec des fonctionnalités de pipeline.

Vous devez écrire un script qui interroge Jenkins pour obtenir des informations sur les travaux en cours et vérifier si un travail du même type est en cours d'exécution. .__ Pour ce faire, vous devez utiliser l'API Jenkins REST, documentation que vous pouvez trouver dans le coin inférieur droit de votre page Jenkins . Exemple de script:

#!/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."

J'ai utilisé bash ici, mais vous pouvez utiliser n'importe quel langage . Ensuite, appelez ce script dans votre fichier Jenkins:

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

Donc, il faudra attendre la fin du travail (ne pas confondre avec les mentions d’intégration-test, c’est juste le nom du travail). 

Sachez également que, dans de rares cas, ce script peut provoquer un blocage lorsque les deux tâches sont en attente l'une de l'autre. Par conséquent, vous souhaiterez peut-être mettre en œuvre des stratégies de nombre maximal de tentatives ici au lieu d'une attente infinie.

2
Vladimir Rozhkov

Jusqu'à ce que le plug-in "Throttle Concurrent Builds" ait la prise en charge de Pipeline , une solution consiste à exécuter efficacement un exécuteur du maître avec un libellé requis par votre travail.

Pour ce faire, créez un nouveau noeud dans Jenkins, par exemple un noeud SSH qui se connecte à localhost. Vous pouvez également utiliser l'option de commande pour exécuter slave.jar/swarm.jar en fonction de votre configuration. Donnez au noeud un exécuteur et une étiquette du type "resource-foo", et attribuez également cette étiquette à votre travail. Désormais, un seul travail d'étiquette "resource-foo" peut être exécuté à la fois car il n'y a qu'un seul exécutant avec cette étiquette. Si vous configurez le noeud pour qu'il soit utilisé autant que possible (par défaut) et réduisez le nombre d'exécuteurs maîtres de un, il doit se comporter exactement comme vous le souhaitez, sans modifier le nombre total d'exécuteurs.

1
mrooney

Si vous êtes comme mon équipe, vous aimez disposer de Jobs Jenkins paramétrables et conviviaux que les scripts de pipeline déclenchent par étapes, au lieu de conserver toute cette soupe déclarative/groovy. Malheureusement, cela signifie que chaque construction de pipeline utilise plus de 2 slots d'exécuteur (un pour le script de pipeline et d'autres pour le (s) travail (s) déclenché (s)), de sorte que le danger de blocage devient très réel. 

J'ai cherché partout des solutions à ce dilemme, et disableConcurrentBuilds () empêche uniquement le même travail (branche) de s'exécuter deux fois. Cela ne fera pas que les constructions de pipeline de différentes branches fassent la queue et attendent au lieu de prendre de précieux créneaux d'exécution.

Pour nous, une solution astucieuse (et pourtant étonnamment élégante) consistait à limiter les exécuteurs du nœud maître à 1 et à obliger les scripts de pipeline à s'en servir (et à lui seul), puis à brancher un agent esclave local à Jenkins d'autre travail.

0
JohannSig