如何使Pipeline作业等待所有触发的并行作业?

时间:2016-10-20 00:13:56

标签: jenkins groovy jenkins-pipeline

我将Groovy脚本作为Jenkins管道工作的一部分,如下所示:

node {
    stage('Testing') {
        build job: 'Test', parameters: [string(name: 'Name', value: 'Foo1')], quietPeriod: 2, wait: false
        build job: 'Test', parameters: [string(name: 'Name', value: 'Bar1')], quietPeriod: 2, wait: false
        build job: 'Test', parameters: [string(name: 'Name', value: 'Baz1')], quietPeriod: 2, wait: false
        build job: 'Test', parameters: [string(name: 'Name', value: 'Foo2')], quietPeriod: 2, wait: false
        build job: 'Test', parameters: [string(name: 'Name', value: 'Bar2')], quietPeriod: 2, wait: false
        build job: 'Test', parameters: [string(name: 'Name', value: 'Baz2')], quietPeriod: 2, wait: false
    }
}

并行执行多个其他自由式作业,因为wait标志设置为false。但是,当所有工作完成时,我希望调用者工作完成。目前,管道工作会触发所有工作并在几秒钟后自行完成,这不是我想要的,因为我无法跟踪总时间,而且我无法一次性取消所有触发的工作。

当所有并行作业完成后,如何更正管道作业的上述脚本?

我试图在waitUntil {}区块中包装构建作业,但它没有用。

5 个答案:

答案 0 :(得分:20)

您应该使用管道 parallel 表达式,它将等待所有生成的作业/子任务完成:

stage('testing') {
    def branches = [:]

    for(i = 0; i < params.size(); i += 1) {
        def param = params[i]

        branches["Test${i}"] = {
            build job: 'Test', parameters: [string(name: 'Name', value: param)], quietPeriod: 2
        }
    }
    parallel branches
}

您可以在jenkins.io

的管道文档中找到更多示例

答案 1 :(得分:4)

遇到同样的问题,找到可行的解决方案。只需使用foreach。

stage('testing') {
    def jobs = [:]

    [1,2,3,4,5].each{
        i -> jobs["Test${i}"] = {
            build job: 'Test', 
            parameters: [string(name: 'theparam', value: "${i}")],
            quietPeriod: 2
        }
    }
    parallel jobs
}

答案 2 :(得分:3)

但是@agg3l's example无法处理多个作业。

Map jobResults = [:]

Boolean failedJobs = false
def buildJobWithParams(def jobs_list, Map results) {
  def branches = [:]    
  for(job in jobs_list)
  {
    print job
    branches["Test-${job}"] = {
       def jobBuild = build job: job, propagate: false
       def jobResult = jobBuild.getResult()
       echo "Build of '${job}' returned result: ${jobResult}"
       results[job] = jobResult
    }
  }    
  return branches
}

stage('Run integration tests') {
      steps {
            def job_branch = buildJobWithParams(item_list, jobResults)
            print job_branch
            parallel job_branch
          }
}

item_list有多个作业,但它只会多次执行上一个作业。

答案 3 :(得分:2)

这对我有用。触发3个工作。等待他们完成。 注意额外的“->”来指定常规闭包。 我在每个循环上都有一个->,在并行线上有一个。 这意味着在运行并行部分时将评估该值。

def jobsString = "job1,job2,job3"
ArrayList jobsList = jobsString.split('\\,')

def parallelJobs2Run = [:]
jobsList.each { job ->
    echo "Going to parallel for job ${job}"
    parallelJobs2Run["${job}"] = { ->
        echo "Calling job ${job}"
        jobResults=build job: "${pathJenkinsFolder}${job}",
        parameters: [
            string(name: 'param1', value: "${value1}"),
            string(name: 'param2', value: "${value2}")
        ],
        propagate: true,
        wait: true

        // List of values: https://stackoverflow.com/questions/46262862/how-to-i-get-the-url-of-build-triggered-with-build-step-on-jenkins
        buildNumber = ${jobResults.number}
        echo "${job} Build number |${buildNumber}| result: |${jobResults.result}|"
        echo "See details on: |${jobResults.absoluteUrl}|"
    }
};
parallel parallelJobs2Run

答案 4 :(得分:0)

另一种基本上做同样事情的方法是将您的工作包装在一个单独的阶段,然后将所有子阶段包装在 parallel{} 中,如下所示:

stage('Trigger all dependent jobs') {
    parallel {
        stage('Trigger task 1') {
            steps {
                build job: "task-1"
            }
        }
        stage('Trigger task 2') {
            steps {
                build job: "task-2"
            }
        }
        stage('Trigger task 3') {
            steps {
                build job: "task-3"
            }
        }
    }   
}

这种方法允许您在每个并行阶段做任何您想做的事情 - 上述任务很可能与 Jenkins 工作完全不同(彼此之间)。

此外,上述方法(据我所知)代表了声明性管道语法。