# Use parallel to run another parallel stages

**URL:** <https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147>\
**Category:** Ask a question\
**Tags:** question, pipeline\
**Created:** [February 1, 2024, 3:54am UTC](https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147 "2024-02-01T03:54:32Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![longkang](https://avatars.discourse-cdn.com/v4/letter/l/e9c0ed/32.png) [@longkang](https://community.jenkins.io/u/longkang)\
**Post date:** [February 1, 2024, 3:54am UTC](https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147/1 "2024-02-01T03:54:32Z")

</div>

Hi Community,

I have one type of test(tlc test), and it has two stages that are `setup` and `run` runs in parallel. Now, I want to add another type of test(qlc test) and try to reuse the existing setup and run job. However, when I try to run this, only one type of test gets bootup instead of two.

Here is my test script:

```auto
def modules = ["tlc","qlc"]
def failFast = false
def builds = [:]
for(module in modules){
    def item = module+"-test"
    println("${item} is running")
    builds[module] = {
        
            def run = [:]
            
            run[module+"-setup"] = {
                build job : "down1",parameters:[
                    string(name: 'type', value: module)
                ]
            }
            
            run[module+"-test"] = {
                build job : "down2",parameters:[
                    string(name: 'type', value: module)
                ]
            }
            run.failFast = true
            parallel run
    }
    
}

builds.failFast = failFast
parallel builds

```

Pipeline result:  
As you can see, the downstream job only bootup down1-2 #9.

```auto
11:44:55 tlc-test is running
11:44:55 [Pipeline] echo
11:44:55 qlc-test is running
11:44:55 [Pipeline] parallel
11:44:55 [Pipeline] { (Branch: tlc)
11:44:55 [Pipeline] { (Branch: qlc)
11:44:56 [Pipeline] parallel
11:44:56 [Pipeline] { (Branch: qlc-setup)
11:44:56 [Pipeline] { (Branch: qlc-test)
11:44:56 [Pipeline] parallel
11:44:56 [Pipeline] { (Branch: qlc-setup)
11:44:56 [Pipeline] { (Branch: qlc-test)
11:44:56 [Pipeline] build (Building down1)
11:44:56 Scheduling project: down1
11:44:56 [Pipeline] build (Building down2)
11:44:56 Scheduling project: down2
11:44:56 [Pipeline] build (Building down1)
11:44:56 Scheduling project: down1
11:44:56 [Pipeline] build (Building down2)
11:44:56 Scheduling project: down2
11:45:05 Starting building: down2 #9
11:45:05 Starting building: down2 #9
11:45:05 Starting building: down1 #9
11:45:05 Starting building: down1 #9
11:45:15 Build down1 #9 completed: SUCCESS
11:45:15 Build down1 #9 completed: SUCCESS
11:45:15 [Pipeline] }
11:45:15 [Pipeline] }
11:45:25 Build down2 #9 completed: SUCCESS
11:45:25 Build down2 #9 completed: SUCCESS
11:45:25 [Pipeline] }
11:45:25 [Pipeline] // parallel
11:45:25 [Pipeline] }
11:45:25 [Pipeline] }
11:45:25 [Pipeline] // parallel
11:45:25 [Pipeline] }
11:45:25 [Pipeline] // parallel
11:45:25 [Pipeline] End of Pipeline
11:45:25 Finished: SUCCESS

```

---

<div class="post-metadata">

**Author:** ![stuartrowe](https://dub1.discourse-cdn.com/flex013/user_avatar/community.jenkins.io/stuartrowe/32/4448_2.png) [@stuartrowe](https://community.jenkins.io/u/stuartrowe)\
**Post date:** [February 7, 2024, 8:22am UTC](https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147/2 "2024-02-07T08:22:38Z")

</div>

Using `for-in` loops in groovy-cps is a known problem IIRC. I would re-write this using `collectEntries` to populate the `builds` map instead:

```auto
def modules = ["tlc","qlc"]
def failFast = false
def builds = modules.collectEntries { module ->
    return [(module): {
        def item = module+"-test"
        println("${item} is running")
        
        def run = [:]
        run[module+"-setup"] = {
            build job : "down1",parameters:[
                string(name: 'type', value: module)
            ]
        }
            
        run[module+"-test"] = {
            build job : "down2",parameters:[
                string(name: 'type', value: module)
            ]
        }
        run.failFast = true
        parallel run
    }]
}
builds.failFast = failFast
parallel builds

```

---

<div class="post-metadata">

**Author:** ![longkang](https://avatars.discourse-cdn.com/v4/letter/l/e9c0ed/32.png) [@longkang](https://community.jenkins.io/u/longkang)\
**Post date:** [February 18, 2024, 2:41am UTC](https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147/3 "2024-02-18T02:41:14Z")

</div>

Thanks, @stuartrowe

This really solves my problem.

---

<div class="post-metadata">

**Author:** ![lemeurherve](https://dub1.discourse-cdn.com/flex013/user_avatar/community.jenkins.io/lemeurherve/32/17166_2.png) [@lemeurherve](https://community.jenkins.io/u/lemeurherve)\
**Post date:** [October 5, 2025, 11:06pm UTC](https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147/4 "2025-10-05T23:06:21Z")

</div>

@stuartrowe Is there any benefit using `collectEntries` instead of `each` or are they similar in their behavior?

---

<div class="post-metadata">

**Author:** ![stuartrowe](https://dub1.discourse-cdn.com/flex013/user_avatar/community.jenkins.io/stuartrowe/32/4448_2.png) [@stuartrowe](https://community.jenkins.io/u/stuartrowe)\
**Post date:** [October 6, 2025, 1:13am UTC](https://community.jenkins.io/t/use-parallel-to-run-another-parallel-stages/12147/5 "2025-10-06T01:13:13Z")

</div>

I think `collectEntries` simplifies building the `builds` map that is used as the argument to the `parallel` step call. You could also iterate over the list with `each` and insert entries into a map declared earlier.

> **[Iterable (Groovy JDK enhancements)](https://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Iterable.html#collectEntries(groovy.lang.Closure))**
