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

如何为Jenkins PipelineJob添加lockableResources锁避免并发执行?

为Jenkins流水线添加全局锁以避免多实例同时运行

问题背景

需要给Jenkins流水线添加锁,防止同一流水线的多个实例同时执行。已完成前置配置:

  • 在plugins.txt中安装lockable-resources插件
  • 在casc.yaml中声明锁资源:
lockableResourcesManager:
    declaredResources:
      - name: "host-1-lock"
        description: "Lock to run jobs on host 1"

尝试过程与问题

1. 在JobDSL中直接添加锁

尝试在pipelineJob定义里添加锁逻辑,期望锁在整个Job周期内保持:

pipelineJob('Test_Job-2') {
    quietPeriod(0)
    triggers {
        cron('H 6 * * *')
    }
    lockableResources('host-1-lock') // 此处报错
    parameters {
        labelParam('Node_Select') {
            defaultValue('host1')
            allNodes('allCases', 'IgnoreOfflineNodeEligibility')
        }
    }
    definition {
        cps {
            script(readFileFromWorkspace('scripts/mypipeline.jenkinsfile'))
        }
    }
}

报错信息:

ERROR: (script, line 6) No signature of method: javaposse.jobdsl.dsl.jobs.WorkflowJob.lockableResources() is applicable for argument types: (java.lang.String) values: [host-1-lock]

尝试lock("host-1-lock")语法、将lock()放入definition块内,均无效。

2. 在Jenkinsfile的stages外添加锁

将锁逻辑移至scripts/mypipeline.jenkinsfile,直接写在stages块外:

pipeline {
    options {
        ansiColor('xterm')
    }
    agent any
    stages {
        lock('host-1-lock') // 此处报错lock未定义
        stage ('Build 1') {
            when {
                allOf {
                    expression { return params.RUN_BUILD }
                }
            }
            steps {
                catchError(stageResult: 'FAILURE') {
                    retry(count: 7) {
                        timeout(time: 180, unit: 'MINUTES') {
                            script {
                                def result = buildLabJob(STAGE_BUILD)
                                sh "exit $result"
                            }
                        }
                    }
                }
            }
            post {
                failure {
                    log("warn", "Build failed, skipping remaining stages")
                    script {
                        skipRemainingStages = true
                    }
                }
            }
        }
        // 其他阶段省略...
    }
}

报错提示lock未定义,查文档得知lock通常在stage内使用,但需求是让锁覆盖多个阶段,保持整个流水线执行期间不释放。

3. 单独设置获取/释放锁阶段

尝试添加专门的阶段来管理锁的获取与释放:

stage('Acquire Lock') {
    steps {
        lock(resource: 'Lab240-lock') {
            echo 'Lock acquired'
        }
    }
}
// 其他业务阶段...
stage('Release Lock') {
    steps {
        lock(resource: 'Lab240_lock', inversePrecedence: true) {
            echo 'Lock released'
        }
    }
}

效果不符合预期:流水线1获取锁后运行时,流水线2启动后也能立即获取锁,两个流水线交替执行阶段,无法实现流水线2完全等待流水线1结束后再运行。

正确解决方案

要实现整个流水线期间持有锁,需将所有业务阶段包裹在一个lock块内,修改后的Jenkinsfile如下:

pipeline {
    options {
        ansiColor('xterm')
    }
    agent any
    stages {
        stage('Run with Global Lock') {
            steps {
                lock(resource: 'host-1-lock') {
                    // 所有需要锁保护的阶段逻辑全部移入此块
                    stage ('Build 1') {
                        when {
                            allOf {
                                expression { return params.RUN_BUILD }
                            }
                        }
                        steps {
                            catchError(stageResult: 'FAILURE') {
                                retry(count: 7) {
                                    timeout(time: 180, unit: 'MINUTES') {
                                        script {
                                            def result = buildLabJob(STAGE_BUILD)
                                            sh "exit $result"
                                        }
                                    }
                                }
                            }
                        }
                        post {
                            failure {
                                log("warn", "Build failed, skipping remaining stages")
                                script {
                                    skipRemainingStages = true
                                }
                            }
                        }
                    }
                    stage ('Build Cluster DPU') {
                        when {
                            allOf {
                                expression { return params.RUN_BUILD }
                            }
                        }
                        steps {
                            catchError(stageResult: 'FAILURE') {
                                retry(count: 7) {
                                    timeout(time: 360, unit: 'MINUTES') {
                                        script {
                                            def result = buildLabJob(STAGE_BUILD_JOBS)
                                            sh "exit $result"
                                        }
                                    }
                                }
                            }
                        }
                        post {
                            failure {
                                log("warn", "Build failed, skipping remaining stages")
                                script {
                                    skipRemainingStages = true
                                }
                            }
                        }
                    }
                    stage ('Deploy Custom') {
                        when { 
                            allOf {
                                expression { !skipRemainingStages }
                                expression { return params.RUN_CUSTOM }
                            }
                        }
                        steps {
                            catchError(stageResult: 'FAILURE') {
                                script {
                                    def result = buildLabJob(STAGE_CUSTOM_JOBS)
                                    sh "exit $result"
                                }
                            }
                        }
                        post {
                            failure {
                                script {
                                    skipRemainingStages = true
                                }
                            }
                        }        
                    }
                }
            }
        }
    }
}

原理说明

  • lock块进入时会获取指定资源锁,直到块内所有逻辑(包括嵌套的所有stage)执行完毕才会释放锁
  • 所有业务阶段都在锁的保护范围内,同一时间仅允许一个流水线实例执行这些阶段
  • 注意:lock必须放在steps块内,因此需要用一个父stage来包裹所有需要锁保护的内容

额外注意事项

  1. 确保lockable-resources插件版本正确,且Jenkins已重启加载配置
  2. 锁资源名称需与casc.yaml中声明的完全一致(注意拼写,如之前的Lab240-lock与Lab240_lock拼写不一致会导致锁失效)
  3. 若流水线需在特定节点执行,需确保锁与节点选择逻辑不冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:20:07