Search code examples
jenkinsgroovyjenkins-pipeline

Parallel jenkins job using a for loop


I am trying to run a list of builds in parallel using a for loop because the code is getting bigger and bigger.

I have a global list with the names of projects

@Field def final String[] projectsList = ['project1','project2', 'project3'....]
stages {
    stage('Parallel Build') {
        steps{
            script{
                   def branches = [:]
                   for(int i = 0;i<15;i++) {
                        branches["Build "+projectsList[i]] = {buildProject(i)}
                   }
                   parallel branches
             }
     }

}           

The Build projects method takes the name of the project from the global list and builds it using maven.

The thing is, the project at index 15 (Which shouldn't be built) is building 15 times in parallel. As if it is waiting until the for loop ends and then assigns the same available i value (15) in this case to all the methods.

Do you have any idea how can I solve this ?


Solution

  • Your issue lies with how you make (mis)use of the Groovy closure concept, i.e. the part where you define a closure in the loop's body that makes use of the iteration variable i, that is { buildProject(i) } :)

    What happens exactly is nicely described here. This is, indeed, a common "gotcha" with other languages offering functional programming features, as well (e.g. JavaScript).

    The easiest (hardly the most elegant, though) solution is to define a variable within the loop that receives the current i value and make use of that within the closure:

    def branches = [:]
    for(i = 0; i < 15; i++) {
        def curr = i
        branches["Build ${projectsList[i]}"] = { buildProject(curr) }
    }
    parallel branches
    

    (I've also used a bit more idiomatic Groovy like String interpolation).

    A more elegant, less verbose, Groovy-like solution that iterates through the range of projects would be:

    (0..<projectsList.size()).each { i ->
        branches["Build ${projectsList[i]}"] = { buildProject(i) }
    }