如何避免Jenkins并行创建阶段时流水线视图的阶段矩阵被截断?
现有一段包含并行阶段的Jenkins流水线代码:
Random random = new Random(); node { def distros = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; parallel(distros.indexed().collectEntries { index, distro -> [("${distro}") : { println("start stage ${index}: ${distro}"); // 阶段创建前的耗时操作(比如锁定资源) sh("sleep ${Math.abs(random.nextInt()) % 3}"); stage("Build ${distro}") { "${distro}" } }] }) }
尽管每次构建的阶段数量和名称完全一致,但由于parallel执行导致阶段创建顺序随机,基于Pipeline-Stage-View-Plugin的构建阶段矩阵视图会被截断,仅保留最后一次构建记录。
有人提出一种简单的强制顺序方法:在每个阶段前等待递增时长,示例代码如下:
Random random = new Random(); node { def distros = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]; parallel(distros.indexed().collectEntries { index, distro -> [("${distro}") : { println("start stage ${index}: ${distro}"); // 阶段创建前的耗时操作(比如锁定资源) sh("sleep ${Math.abs(random.nextInt()) % 3}"); // 强制顺序 sh("sleep ${index * 4}"); stage("Build ${distro}") { "${distro}" } }] }) }
但这种方法不够优雅,会额外耗费大量时间;如果每个distro包含多个阶段,还会导致并行构建退化为串行执行。
需求:希望在流水线视图中完整查看所有历史构建记录,是否有更优方案?能否预定义阶段顺序?
可以通过提前固定并行分支顺序或给阶段指定固定排序参数来解决问题,让Pipeline-Stage-View插件识别到稳定的阶段结构,避免历史构建被截断。
方案1:固定并行分支的顺序
Jenkins的parallel步骤会保留传入Map的键顺序(Groovy 2.4及以上版本支持有序Map),我们可以直接基于有序的distros列表生成并行分支,确保分支键的顺序与预期的阶段顺序完全一致:
node { def distros = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] // 按distros顺序构建并行分支Map,分支键直接使用阶段名称 def parallelStages = [:] distros.each { distro -> def stageName = "Build ${distro}" parallelStages[stageName] = { println("start stage: ${distro}") // 阶段创建前的耗时操作 sh("sleep ${Math.abs(new Random().nextInt()) % 3}") stage(stageName) { echo "Processing ${distro}" } } } // 按固定顺序执行并行分支 parallel(parallelStages) }
核心逻辑:让并行分支的键名与阶段显示名称一致,且键的顺序严格遵循distros的顺序。Pipeline-Stage-View插件会基于这个固定顺序渲染阶段矩阵,不会因实际执行顺序的随机性截断历史构建。
方案2:给阶段指定order参数(需新版Pipeline插件支持)
如果使用的Jenkins Pipeline插件版本在2.200及以上,可以在定义stage时通过order参数强制固定每个阶段的显示顺序:
node { def distros = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] parallel(distros.indexed().collectEntries { index, distro -> [("${distro}") : { println("start stage ${index}: ${distro}") sh("sleep ${Math.abs(new Random().nextInt()) % 3}") // 指定order参数,数值越小,阶段在视图中越靠前 stage("Build ${distro}", order: index + 1) { echo "Processing ${distro}" } }] }) }
通过给每个阶段设置唯一且递增的order值,不管实际执行顺序如何,Pipeline-Stage-View都会按照预设的顺序排列阶段,历史构建的阶段矩阵结构会完全一致,不会被截断。
方案优势
- 无需额外等待时间,完全保留并行构建的执行效率
- 即使每个
distro包含多个阶段,只要保持分支顺序或order参数固定,不会触发串行化 - 历史构建的阶段矩阵结构稳定,可完整查看所有构建记录
内容的提问来源于stack exchange,提问作者frans

