Jenkins Jira Pipeline并发更新问题:Fix Version被意外移除
解决Jenkins流水线并发更新Jira Fix Version的脏写问题
问题背景
当前使用的Jenkins流水线代码用于给指定Jira问题追加Fix Version,代码如下:
stage('JIRA') { def searchResults = jiraJqlSearch jql: "project = ${jiraProjectKey} AND issuekey = ${issueKey}'" def issues = searchResults.data.issues for (i = 0; i <issues.size(); i++) { def result = jiraGetIssue idOrKey: issues[i].key def newVersion = jiraNewVersion version: [name: "${newVersion}", project: "${jiraProjectKey}"] def fixVersions = result.data.fields.fixVersions << newVersion.data def testIssue = [fields: [fixVersions: fixVersions]] response = jiraEditIssue idOrKey: issues[i].key, issue: testIssue } } }
当多个独立流水线并发更新同一Jira问题的不同Fix Version时,会出现随机丢失版本的脏写问题:例如Job1添加1.1、Job2添加2.1、Job3添加3.1,最终问题可能仅保留1.1和3.1,2.1被移除(活动历史显示该版本被删除)。
问题根源
原代码采用"读取-修改-写入"的全量更新模式:先读取当前的Fix Version列表,追加新版本后再将整个列表写回Jira。并发场景下,多个流水线会同时读取到相同的初始版本列表,后续的写入操作会互相覆盖,导致中间添加的版本丢失。
解决方案:使用Jira增量更新语法
直接利用Jira REST API的增量更新能力,通过add动作单独追加新的Fix Version,无需读取现有列表再覆盖。修改后的流水线代码如下:
stage('JIRA') { def searchResults = jiraJqlSearch jql: "project = ${jiraProjectKey} AND issuekey = ${issueKey}" def issues = searchResults.data.issues for (i = 0; i < issues.size(); i++) { def issueKey = issues[i].key // 创建目标版本(可添加存在性检查避免重复创建) def newVersion = jiraNewVersion version: [name: "${newVersion}", project: "${jiraProjectKey}"] // 构造增量更新的请求体,仅追加新版本 def updatePayload = [ update: [ fixVersions: [ [add: newVersion.data] ] ] ] // 执行增量更新 response = jiraEditIssue idOrKey: issueKey, issue: updatePayload } } }
优化补充:避免重复创建版本
如果同一版本可能被多个流水线创建,可以先检查版本是否存在,存在则直接复用:
def targetVersion try { // 尝试获取已存在的版本 def existingVersion = jiraGetVersion versionOrId: "${newVersion}", project: "${jiraProjectKey}" targetVersion = existingVersion.data } catch (Exception e) { // 版本不存在则创建 targetVersion = jiraNewVersion version: [name: "${newVersion}", project: "${jiraProjectKey}"].data }
原理说明
使用update字段配合add动作的请求体,会让Jira直接将指定版本追加到问题的Fix Version列表中,每个请求都是独立的原子操作,无需依赖读取到的旧数据,从根本上避免了并发场景下的脏写冲突。
内容的提问来源于stack exchange,提问作者Stephen Paulin
相关产品推荐
相关产品推荐

