Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: 通过api保存的新版本可能覆盖旧版本 #11418 解决发布和触发并发问题 #11489

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ data class PipelineResourceVersion(
@get:Schema(title = "记录版本号", required = true)
val version: Int,
@get:Schema(title = "JSON编排内容(POJO)", required = true)
val model: Model,
var model: Model,
@get:Schema(title = "YAML编排内容", required = false)
var yaml: String?,
@get:Schema(title = "YAML编排版本", required = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import com.tencent.devops.process.engine.cfg.PipelineIdGenerator
import com.tencent.devops.process.engine.cfg.VersionConfigure
import com.tencent.devops.process.engine.common.VMUtils
import com.tencent.devops.process.engine.control.lock.PipelineModelLock
import com.tencent.devops.process.engine.control.lock.PipelineReleaseLock
import com.tencent.devops.process.engine.dao.PipelineBuildSummaryDao
import com.tencent.devops.process.engine.dao.PipelineInfoDao
import com.tencent.devops.process.engine.dao.PipelineModelTaskDao
Expand Down Expand Up @@ -1346,6 +1347,65 @@ class PipelineRepositoryService constructor(
).map { it.key to str2model(it.value, it.key) }.toMap()
}

/**
* 获取所有本次构建触发需要的信息
* 并在获取过程中增加并发锁,防止流水线发布版本期间触发读取脏数据
*/
fun getBuildTriggerInfo(
projectId: String,
pipelineId: String,
version: Int?
): Triple<PipelineInfo, PipelineResourceVersion, Boolean> {
PipelineReleaseLock(redisOperation, pipelineId).use {
val pipelineInfo = getPipelineInfo(
projectId = projectId,
pipelineId = pipelineId
) ?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_PIPELINE_NOT_EXISTS,
params = arrayOf(pipelineId)
)
if (version == null) {
val defaultVersion = getPipelineResourceVersion(
projectId = projectId,
pipelineId = pipelineId
) ?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_NO_PIPELINE_EXISTS_BY_ID,
params = arrayOf(pipelineId)
)
// 正式执行时,当前最新版本可能是草稿,则作为调试执行
return Triple(
pipelineInfo,
defaultVersion,
defaultVersion.status == VersionStatus.COMMITTING
)
} else {
val targetResource = getPipelineResourceVersion(
projectId = projectId,
pipelineId = pipelineId,
version = version
) ?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_NO_PIPELINE_VERSION_EXISTS_BY_ID,
params = arrayOf(version.toString())
)
return if (targetResource.status == VersionStatus.COMMITTING) {
Triple(pipelineInfo, targetResource, true)
} else {
val releaseVersion = getPipelineResourceVersion(
projectId = projectId,
pipelineId = pipelineId
) ?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_PIPELINE_MODEL_NOT_EXISTS
)
Triple(pipelineInfo, releaseVersion, false)
}
}
}
}

/**
* 获取编排版本的通用方法
* 1 如果指定了[version]则一定按照version号查询版本
Expand All @@ -1356,25 +1416,26 @@ class PipelineRepositoryService constructor(
projectId: String,
pipelineId: String,
version: Int? = null,
includeDraft: Boolean? = false
includeDraft: Boolean? = false,
queryDslContext: DSLContext? = null
): PipelineResourceVersion? {
// TODO 取不到则直接从旧版本表读,待下架
val resource = if (version == null) {
if (includeDraft == true) pipelineResourceVersionDao.getDraftVersionResource(
dslContext = dslContext,
dslContext = queryDslContext ?: dslContext,
projectId = projectId,
pipelineId = pipelineId
) else null
} else {
pipelineResourceVersionDao.getVersionResource(
dslContext = dslContext,
dslContext = queryDslContext ?: dslContext,
projectId = projectId,
pipelineId = pipelineId,
version = version,
includeDraft = includeDraft
)
} ?: pipelineResourceDao.getReleaseVersionResource(
dslContext = dslContext,
dslContext = queryDslContext ?: dslContext,
projectId = projectId,
pipelineId = pipelineId
)
Expand Down Expand Up @@ -1405,7 +1466,7 @@ class PipelineRepositoryService constructor(
}
}
pipelineCallbackDao.list(
dslContext = dslContext,
dslContext = queryDslContext ?: dslContext,
projectId = projectId,
pipelineId = pipelineId,
event = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import com.tencent.devops.common.api.util.JsonUtil
import com.tencent.devops.common.audit.ActionAuditContent
import com.tencent.devops.common.auth.api.ActionId
import com.tencent.devops.common.auth.api.ResourceTypeId
import com.tencent.devops.common.pipeline.Model
import com.tencent.devops.common.pipeline.dialect.PipelineDialectUtil
import com.tencent.devops.common.pipeline.enums.BuildFormPropertyType
import com.tencent.devops.common.pipeline.enums.ChannelCode
Expand All @@ -55,6 +54,7 @@ import com.tencent.devops.process.engine.service.PipelineRepositoryService
import com.tencent.devops.process.engine.service.PipelineRuntimeService
import com.tencent.devops.process.pojo.BuildId
import com.tencent.devops.process.pojo.app.StartBuildContext
import com.tencent.devops.process.pojo.pipeline.PipelineResourceVersion
import com.tencent.devops.process.service.PipelineAsCodeService
import com.tencent.devops.process.service.ProjectCacheService
import com.tencent.devops.process.util.BuildMsgUtils
Expand Down Expand Up @@ -128,17 +128,15 @@ class PipelineBuildService(
pipelineParamMap: MutableMap<String, BuildParameters>,
channelCode: ChannelCode,
isMobile: Boolean,
model: Model,
yamlVersion: String?,
resource: PipelineResourceVersion,
signPipelineVersion: Int? = null, // 指定的版本
frequencyLimit: Boolean = true,
buildNo: Int? = null,
startValues: Map<String, String>? = null,
handlePostFlag: Boolean = true,
webHookStartParam: MutableMap<String, BuildParameters> = mutableMapOf(),
triggerReviewers: List<String>? = null,
debug: Boolean? = false,
versionName: String? = null
debug: Boolean? = false
): BuildId {

var acquire = false
Expand Down Expand Up @@ -195,11 +193,11 @@ class PipelineBuildService(

// 如果指定了版本号,则设置指定的版本号
pipeline.version = signPipelineVersion ?: pipeline.version
val originModelStr = JsonUtil.toJson(model, formatted = false)
val originModelStr = JsonUtil.toJson(resource.model, formatted = false)
// 只有新构建才需要填充Post插件与质量红线插件
if (!pipelineParamMap.containsKey(PIPELINE_RETRY_BUILD_ID)) {
pipelineElementService.fillElementWhenNewBuild(
model = model,
model = resource.model,
projectId = pipeline.projectId,
pipelineId = pipeline.pipelineId,
startValues = startValues,
Expand Down Expand Up @@ -243,16 +241,17 @@ class PipelineBuildService(
pipelineParamMap = pipelineParamMap,
webHookStartParam = webHookStartParam,
// 解析出定义的流水线变量
realStartParamKeys = model.getTriggerContainer().params.map { it.id },
realStartParamKeys = resource.model.getTriggerContainer()
.params.map { it.id },
debug = debug ?: false,
versionName = versionName,
yamlVersion = yamlVersion
versionName = resource.versionName,
yamlVersion = resource.yamlVersion
)

val interceptResult = pipelineInterceptorChain.filter(
InterceptData(
pipelineInfo = pipeline,
model = model,
model = resource.model,
startType = startType,
buildId = buildId,
runLockType = setting.runLockType,
Expand All @@ -272,7 +271,7 @@ class PipelineBuildService(
)
}

return pipelineRuntimeService.startBuild(fullModel = model, context = context)
return pipelineRuntimeService.startBuild(fullModel = resource.model, context = context)
} finally {
if (acquire) {
simpleRateLimiter.release(lockKey = lockKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,21 +224,15 @@ class SubPipelineStartUpService @Autowired constructor(
runMode: String,
parentExecuteCount: Int?
): BuildId {

val readyToBuildPipelineInfo = pipelineRepositoryService.getPipelineInfo(projectId, pipelineId, channelCode)
?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
params = arrayOf(pipelineId),
errorCode = ProcessMessageCode.ERROR_PIPELINE_NOT_EXISTS
)
val (readyToBuildPipelineInfo, resource, _) = pipelineRepositoryService.getBuildTriggerInfo(
projectId, pipelineId, null
)
if (readyToBuildPipelineInfo.locked == true) {
throw ErrorCodeException(errorCode = ProcessMessageCode.ERROR_PIPELINE_LOCK)
}
if (readyToBuildPipelineInfo.latestVersionStatus?.isNotReleased() == true) {
throw ErrorCodeException(
errorCode = ProcessMessageCode.ERROR_NO_RELEASE_PIPELINE_VERSION
)
}
if (readyToBuildPipelineInfo.latestVersionStatus?.isNotReleased() == true) throw ErrorCodeException(
errorCode = ProcessMessageCode.ERROR_NO_RELEASE_PIPELINE_VERSION
)
val parentPipelineInfo = pipelineRepositoryService.getPipelineInfo(
projectId = parentProjectId,
pipelineId = parentPipelineId
Expand All @@ -259,15 +253,7 @@ class SubPipelineStartUpService @Autowired constructor(

val startEpoch = System.currentTimeMillis()
try {
val resource = pipelineRepositoryService.getPipelineResourceVersion(
projectId, pipelineId, readyToBuildPipelineInfo.version
) ?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_PIPELINE_MODEL_NOT_EXISTS
)
val model = resource.model

val triggerContainer = model.getTriggerContainer()
val triggerContainer = resource.model.getTriggerContainer()
// #6090 拨乱反正
val params = buildParamCompatibilityTransformer.parseTriggerParam(
userId = userId, projectId = projectId, pipelineId = pipelineId,
Expand Down Expand Up @@ -335,10 +321,8 @@ class SubPipelineStartUpService @Autowired constructor(
pipelineParamMap = params,
channelCode = channelCode,
isMobile = isMobile,
model = model,
frequencyLimit = false,
versionName = resource.versionName,
yamlVersion = resource.yamlVersion
resource = resource,
frequencyLimit = false
)
// 更新父流水线关联子流水线构建id
pipelineTaskService.updateSubBuildId(
Expand All @@ -354,13 +338,6 @@ class SubPipelineStartUpService @Autowired constructor(
}
}

private fun getModel(projectId: String, pipelineId: String, version: Int? = null) =
pipelineRepositoryService.getPipelineResourceVersion(projectId, pipelineId, version)?.model
?: throw ErrorCodeException(
statusCode = Response.Status.NOT_FOUND.statusCode,
errorCode = ProcessMessageCode.ERROR_PIPELINE_MODEL_NOT_EXISTS
)

/**
* 解析子流水线启动参数
* @param value 子流水线启动参数
Expand Down
Loading