Jenkins配置:单作业成功触发下游构建,避免重复执行
解决Jenkins作业A/B触发1-4避免重复执行的方案
嘿,这个场景我之前帮团队处理过,刚好有几个实用的方案,你可以根据现有作业的结构来选:
方法一:用标记作业+条件触发(适合传统自由风格作业,改动小)
这个思路是给作业1-4加个“已执行”的标记,不管是A还是B触发,先看标记状态,没执行过才跑,跑过就跳过。
步骤1:建一个极简的标记作业
新建一个叫Flag_Jobs_1-4的作业,加一个字符串参数FLAG_ACTION(可选值SET或RESET),然后加个Shell步骤:# 假设我们在Jenkins服务器上存一个标记文件,路径可自行调整 FLAG_FILE="/var/jenkins_home/flags/jobs_1-4_flag" if [ "$FLAG_ACTION" = "SET" ]; then echo "true" > $FLAG_FILE elif [ "$FLAG_ACTION" = "RESET" ]; then echo "false" > $FLAG_FILE fi这个作业的作用就是切换标记状态。
步骤2:修改A和B的触发逻辑
别直接在A/B的构建后操作里触发1-4了,换成「Conditional BuildStep」(需要先安装这个插件):- 先加一个“执行Shell”的条件步骤,检查标记文件的值:
FLAG_FILE="/var/jenkins_home/flags/jobs_1-4_flag" # 如果文件不存在,默认标记为未执行 if [ ! -f $FLAG_FILE ]; then echo "false" > $FLAG_FILE; fi CURRENT_FLAG=$(cat $FLAG_FILE) if [ "$CURRENT_FLAG" = "false" ]; then exit 0; else exit 1; fi - 条件满足(标记为未执行)时,同时触发两个操作:
- 触发作业1、2、3、4(并行或串行都可以)
- 触发标记作业
Flag_Jobs_1-4,传入参数FLAG_ACTION=SET
- 条件不满足时,直接跳过触发逻辑即可。
- 先加一个“执行Shell”的条件步骤,检查标记文件的值:
步骤3:添加标记重置逻辑(可选)
如果需要每天重置标记(比如每天凌晨),给标记作业加个定时触发器,设置H 0 * * *,并传入参数FLAG_ACTION=RESET。
方法二:用Pipeline重构(灵活度拉满,适合长期维护)
如果能把作业改成Pipeline,逻辑会更清晰,也不用依赖太多插件:
方案1:做一个统一的触发调度Pipeline
新建一个Pipeline作业,设置为当A或B成功后触发,然后在脚本里控制:
pipeline { agent any stages { stage('Check if Jobs 1-4 need to run') { steps { script { // 以作业1为例,检查最近一次构建是否是A/B触发且在24小时内 def job1 = Jenkins.instance.getItemByFullName('Job1') def lastValidBuild = job1.getBuilds().find { build -> // 判断是否是A或B触发的 def isTriggeredByAorB = build.causes.any { cause -> cause instanceof hudson.model.Cause.UpstreamCause && (cause.upstreamProject == 'JobA' || cause.upstreamProject == 'JobB') } // 判断是否在最近24小时内 def isRecent = build.timestamp.time > (System.currentTimeMillis() - 24*60*60*1000) isTriggeredByAorB && isRecent } if (!lastValidBuild) { echo 'Jobs 1-4 haven\'t been triggered by A/B recently, starting them...' // 并行触发四个作业 parallel( "Job1": { build job: 'Job1', wait: false }, "Job2": { build job: 'Job2', wait: false }, "Job3": { build job: 'Job3', wait: false }, "Job4": { build job: 'Job4', wait: false } ) } else { echo "Jobs 1-4 were already triggered at ${lastValidBuild.timestamp}, skip." } } } } } }
这样不管A还是B先完成,只要1-4没被触发过,就跑一次,之后再触发就直接跳过。
方案2:给每个作业1-4加自我判断逻辑
如果不想改A/B,直接给作业1-4改成Pipeline,在开头加判断:
pipeline { agent any stages { stage('Pre-check: Avoid duplicate run') { steps { script { def lastBuild = currentBuild.previousBuild if (lastBuild) { // 检查上一次构建是否是A或B触发的,且在有效期内 def isTriggeredByAorB = lastBuild.causes.any { cause -> cause instanceof hudson.model.Cause.UpstreamCause && (cause.upstreamProject == 'JobA' || cause.upstreamProject == 'JobB') } def isWithinValidPeriod = lastBuild.timestamp.time > (System.currentTimeMillis() - 24*60*60*1000) if (isTriggeredByAorB && isWithinValidPeriod) { error "Abort: This job was already triggered by A/B at ${lastBuild.timestamp}, no need to run again." } } } } } // 原来的构建步骤 stage('Build & Deploy') { steps { // 你的原有构建逻辑,比如拉代码、打包、打标签等 } } } }
这样不管A还是B触发这个作业,它都会先自检,符合重复条件就直接终止,避免重复打标签的问题。
方法三:用节流插件快速限制(适合简单场景)
如果只是想让作业1-4在指定时间内只跑一次,装个Throttle Concurrent Builds Plugin就行:
- 给作业1-4分别配置插件:
- 勾选「Throttle this project」
- 设置「Maximum total concurrent builds」为1
- 勾选「Throttle all builds」,然后设置「Cool down period」(比如填1440,代表24小时)
这样不管A还是B触发,作业在冷却期内只会执行一次,后续的触发请求都会被插件拦截。
内容的提问来源于stack exchange,提问作者50th Mersenne Prime
相关产品推荐
相关产品推荐

