How do I implement a retry option for failed stages in Jenkins pipelines?

后端 未结 3 2033
深忆病人
深忆病人 2021-01-30 02:13

I have a Jenkinsfile with multiple stages and one of them is in fact another job (the deploy one) which can fail in some cases.

I know that I can made prompts using Jenk

相关标签:
3条回答
  • 2021-01-30 02:49

    You should be able to combine retry + input to do that Something like that

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

    you could also use timeout for the input if you want it to finish if nobody validates. There is also waitUntil that might be useful but i haven't used it yet

    Edit : WaitUntil seems definitely the best, you should play with it a bit but something like that is cleaner :

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

    By the way, there is doc all of the steps here https://jenkins.io/doc/pipeline/steps

    0 讨论(0)
  • 2021-01-30 02:50

    This gist (not mine) was one of the better options that I found while trying to implement this functionality too. https://gist.github.com/beercan1989/b66b7643b48434f5bdf7e1c87094acb9

    Changed it to a method in a shared library that just did retry or abort for my needs. Also added a max retries and made the timeout variable so that we could change it depending on the job or stage that needs it.

    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;
                    }
                }
            }
        }
    }
    

    Example usage with a max of 2 retries that waits for 60s for input.

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

    Just remember to put nodes inside of the closure so that waiting for an input doesn't block an executor.

    If you have the paid jenkins enterprise Cloudbees has a Checkpoint plugin that can better handle this, but it is not planned to be release for open source Jenkins (JENKINS-33846).

    0 讨论(0)
  • 2021-01-30 02:58

    This one with a nice incremental wait

    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'
     }
    }
    
    0 讨论(0)
提交回复
热议问题