web-dev-qa-db-fra.com

Comment implémenter une option de nouvelle tentative pour les étapes ayant échoué dans les pipelines Jenkins?

J'ai un Jenkinsfile avec plusieurs étapes et l'un d'eux est en fait un autre travail (le déploiement) qui peut échouer dans certains cas.

Je sais que je peux créer des invites à l'aide de Jenkinsfile, mais je ne sais pas vraiment comment implémenter un mécanisme de nouvelle tentative pour ce travail.

Je veux pouvoir cliquer sur l'étape en échec et choisir de la réessayer. jenkins-pipelines-with-stages

54
sorin

Vous devriez être capable de combiner les tentatives et les tentatives pour le faire. Quelque chose comme ça

stage('deploy-test') {
   try {
     build 'yourJob'
   } catch(error) {
     echo "First build failed, let's retry if accepted"
     retry(2) {
        input "Retry the job ?"
        build 'yourJob'
     }
   }
}

vous pouvez également utiliser timeout pour l'entrée si vous souhaitez que celle-ci se termine si personne ne le valide. Il y a aussi waitUntil qui pourrait être utile mais je ne l'ai pas encore utilisé

Edit: WaitUntil semble définitivement le meilleur, vous devriez jouer avec, mais quelque chose comme ça est plus propre:

stage('deploy-test') {
   waitUntil {
     try {
       build 'yourJob'
     } catch(error) {
        input "Retry the job ?"
        false
     }
   }
}

A propos, il y a doc toutes les étapes ici https://jenkins.io/doc/pipeline/steps

31
fchaillou

Ce Gist (pas le mien) était l’une des meilleures options que j’ai trouvées en essayant de mettre en œuvre cette fonctionnalité aussi. https://Gist.github.com/beercan1989/b66b7643b48434f5bdf7e1c87094acb9

Changé en une méthode dans une bibliothèque partagée qui venait juste de réessayer ou d’abandonner pour mes besoins. Nous avons également ajouté un nombre maximal d'essais et créé la variable de délai d'attente afin qu'elle puisse être modifiée en fonction du travail ou de l'étape qui en a besoin.

package com.foo.bar.jenkins

def class PipelineHelper {
    def steps

    PipelineHelper(steps) {
        this.steps = steps
    }

    void retryOrAbort(final Closure<?> action, int maxAttempts, int timeoutSeconds, final int count = 0) {
        steps.echo "Trying action, attempt count is: ${count}"
        try {
            action.call();
        } catch (final exception) {
            steps.echo "${exception.toString()}"
            steps.timeout(time: timeoutSeconds, unit: 'SECONDS') {
                def userChoice = false
                try {
                    userChoice = steps.input(message: 'Retry?', ok: 'Ok', parameters: [
                            [$class: 'BooleanParameterDefinition', defaultValue: true, description: '', name: 'Check to retry from failed stage']])
                } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
                    userChoice = false
                }
                if (userChoice) {
                    if (count <= maxAttempts) {
                        steps.echo "Retrying from failed stage."
                        return retryOrAbort(action, maxAttempts, timeoutMinutes, count + 1)
                    } else {
                        steps.echo "Max attempts reached. Will not retry."
                        throw exception
                    }
                } else {
                    steps.echo 'Aborting'
                    throw exception;
                }
            }
        }
    }
}

Exemple d'utilisation avec un maximum de 2 tentatives en attente d'une attente de 60 secondes.

def pipelineHelper = new PipelineHelper(this)

stage ('Retry Example'){
    pipelineHelper.retryOrAbort({
        node{
            echo 'Here is an example'
            throw new RuntimeException('This example will fail.')
        }
    }, 2, 60)
}

Rappelez-vous simplement de mettre les nœuds à l'intérieur de la fermeture pour que l'attente d'une entrée ne bloque pas un exécuteur.

Si vous avez l'entreprise Jenkins payée, Cloudbees a un plugin Checkpoint qui peut mieux gérer cela, mais il n'est pas prévu de le publier pour Jenkins en open source ( JENKINS-33846 ).

7
dben1713

Celui-ci avec une belle attente incrémentale

stage('deploy-test') {
 def retryAttempt = 0
 retry(2) {
    if (retryAttempt > 0) {
       sleep(1000 * 2 + 2000 * retryAttempt)
    }

    retryAttempt = retryAttempt + 1
    input "Retry the job ?"
    build 'yourJob'
 }
}
6
LuisKarlos