You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jenkins二维并行阶段实现异常:串行阶段重复问题求助

解决Jenkins二维并行阶段重复执行问题

我尝试实现Jenkins二维并行阶段,预期生成12个不同阶段(A1/B1/C1/A2/B3/C2/A3/B3/C3/A4/B4/C4)——3个并行构建分支,每个分支包含4个串行阶段。但实际所有分支都重复执行最后一组串行阶段(C1/C1/C1/C2/C2/C2/C3/C3/C3/C4/C4/C4),Blue Ocean视图和控制台输出都验证了这个问题。

测试代码

build_list = ['B1', 'B2', 'B3']

l1 = ['A1', 'A2', 'A3', 'A4']
l2 = ['B1', 'B2', 'B3', 'B4']
l3 = ['C1', 'C2', 'C3', 'C4']

array_build_list = [ l1, l2, l3 ]

index = 1
index = -index

def parallelStagesMap = build_list.collectEntries {
    index++
    ["${it}" : generateStage(it, index)]
}

def generateStage(job, index) {
    return {
        stage("${job}") {
            echo "This is ${job}"
            script {
                build_project_list = array_build_list[index]
                echo "build_project_list = ${build_project_list}"
                
                for(int i=0; i<build_project_list.size(); i++) {
                    stage(build_project_list[i]) {
                        echo "${build_project_list[i]}"
                    }
                }
            }
        }
    }
}

pipeline {
    agent any

    stages {
        stage("start") {
            steps {
                echo "start"
            }
        }
        stage('parallel stage') {
            steps {
                script {
                    echo "Inside script"
                    parallel parallelStagesMap
                }
            }
        }
    }
}

控制台输出

[Pipeline] Start of Pipeline
[Pipeline] echo
After value B1 at index 0
[Pipeline] echo
After value B2 at index 1
[Pipeline] echo
After value B3 at index 2
[Pipeline] node
Running on Jenkins in /Users/.jenkins/workspace/2D_array_test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (start)
[Pipeline] echo
start
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (parallel stage)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Inside script
[Pipeline] parallel
[Pipeline] { (Branch: B1)
[Pipeline] { (Branch: B2)
[Pipeline] { (Branch: B3)
[Pipeline] stage
[Pipeline] { (B1)
[Pipeline] stage
[Pipeline] { (B2)
[Pipeline] stage
[Pipeline] { (B3)
[Pipeline] echo
This is B1
[Pipeline] sh
[Pipeline] echo
This is B2
[Pipeline] sh
[Pipeline] echo
This is B3
[Pipeline] sh
[Pipeline] script
[Pipeline] {
[Pipeline] script
[Pipeline] {
[Pipeline] script
[Pipeline] {
[Pipeline] echo
build_project_list = [A1, A2, A3, A4]
[Pipeline] echo
build_project_list = [B1, B2, B3, B4]
[Pipeline] echo
build_project_list = [C1, C2, C3, C4]
[Pipeline] stage
[Pipeline] { (C1)
[Pipeline] stage
[Pipeline] { (C1)
[Pipeline] stage
[Pipeline] { (C1)
[Pipeline] echo
C1
[Pipeline] }
[Pipeline] echo
C1
[Pipeline] }
[Pipeline] echo
C1
[Pipeline] }
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (C2)
[Pipeline] stage
[Pipeline] { (C2)
[Pipeline] stage
[Pipeline] { (C2)
[Pipeline] echo
C2
[Pipeline] }
[Pipeline] echo
C2
[Pipeline] }
[Pipeline] echo
C2
[Pipeline] }
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (C3)
[Pipeline] stage
[Pipeline] { (C3)
[Pipeline] stage
[Pipeline] { (C3)
[Pipeline] echo
C3
[Pipeline] }
[Pipeline] echo
C3
[Pipeline] }
[Pipeline] echo
C3
[Pipeline] }
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (C4)
[Pipeline] stage
[Pipeline] { (C4)
[Pipeline] stage
[Pipeline] { (C4)
[Pipeline] echo
C4
[Pipeline] }
[Pipeline] echo
C4
[Pipeline] }
[Pipeline] echo
C4
[Pipeline] }
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] }
[Pipeline] }
[Pipeline] }
[Pipeline] // script
[Pipeline] // script
[Pipeline] // script
[Pipeline] }
[Pipeline] }
[Pipeline] }
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] // stage
[Pipeline] }
[Pipeline] }
[Pipeline] }
[Pipeline] // parallel
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

问题原因

这是Groovy的闭包延迟绑定特性导致的:generateStage返回的闭包不会立即计算index参数的值,而是等到闭包实际执行时才去读取index变量的最终值。循环结束后,index的最终值是2(对应array_build_list的第三个元素l3),所以所有并行分支都使用了l3的阶段列表。

修复方案

方案1:捕获局部变量的索引值

在collectEntries循环中,把当前的index值存入局部变量,让闭包捕获这个局部变量的副本,而非外部变量的引用:

def parallelStagesMap = build_list.collectEntries { item ->
    def currentIndex = index++
    ["${item}" : generateStage(item, currentIndex)]
}

方案2:直接传递目标阶段列表

跳过索引传递,直接把每个分支对应的阶段列表作为参数传给generateStage,彻底避免索引绑定问题:

build_list = ['B1', 'B2', 'B3']

l1 = ['A1', 'A2', 'A3', 'A4']
l2 = ['B1', 'B2', 'B3', 'B4']
l3 = ['C1', 'C2', 'C3', 'C4']

array_build_list = [ l1, l2, l3 ]

def parallelStagesMap = build_list.indexed().collectEntries { idx, item ->
    ["${item}" : generateStage(item, array_build_list[idx])]
}

def generateStage(job, projectList) {
    return {
        stage("${job}") {
            echo "This is ${job}"
            script {
                echo "build_project_list = ${projectList}"
                
                for(int i=0; i<projectList.size(); i++) {
                    stage(projectList[i]) {
                        echo "${projectList[i]}"
                    }
                }
            }
        }
    }
}

pipeline {
    agent any

    stages {
        stage("start") {
            steps {
                echo "start"
            }
        }
        stage('parallel stage') {
            steps {
                script {
                    echo "Inside script"
                    parallel parallelStagesMap
                }
            }
        }
    }
}

两种方案都能让每个并行分支正确绑定对应的串行阶段列表,执行出预期的12个不同阶段。

内容的提问来源于stack exchange,提问作者MatthewKim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:00:54