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
相关产品推荐
相关产品推荐

