Artifactory 5.5.1元数据写入时出现ConcurrentModificationException问题求助
ConcurrentModificationException When Publishing to Specific Artifactory Repository (Groovy Plugin Root Cause & Fix)
我之前碰到过一模一样的问题,这个ConcurrentModificationException的根源很明确:你在同步的afterCreate钩子中执行了会触发同类钩子的操作。具体来说,当你往stage-release仓库上传构件时,钩子会触发repositories.copy把构件复制到release仓库,而这个复制操作本身又会触发release仓库的afterCreate钩子——此时原钩子的执行还没完成,插件系统正在遍历钩子动作集合,新的钩子触发会修改这个集合,直接导致Guava的LinkedHashMultimap抛出并发修改异常。
解决方案1:用异步任务执行复制操作
把复制逻辑放到异步任务里,让当前的afterCreate钩子先执行完毕,再异步处理复制,这样就不会干扰正在遍历的钩子集合。修改后的代码如下:
import org.artifactory.exception.CancelException import org.artifactory.repo.RepoPathFactory import org.artifactory.api.context.ContextHelper storage { afterCreate { item -> def repoKey = item.repoPath.repoKey if (repoKey == 'stage-release') { def sourcePath = RepoPathFactory.create(repoKey, item.repoPath.path) def destPath = RepoPathFactory.create('release', item.repoPath.path) echo "ID is " + item.repoPath.id if (!repositories.exists(destPath)) { echo "MISSING artifact in the release repo, scheduling async copy" // 提交异步任务执行复制逻辑 def executions = ContextHelper.get().beanForType(org.artifactory.api.execution.Executions.class) executions.submitAsync("Copy artifact from stage-release to release", { repositories.copy(sourcePath, destPath) }) } else { echo "FOUND the artifact in the release repo so no need to copy" } } } } def echo(str) { log.warn "########################### " + str; }
解决方案2:复制时直接禁用拦截器(更简洁)
Artifactory 5.x的Groovy API支持在复制操作时禁用拦截器,这样复制构件到release仓库时不会触发afterCreate钩子,从根源上避免循环触发和并发问题。修改复制那一行代码即可:
import org.artifactory.exception.CancelException import org.artifactory.repo.RepoPathFactory storage { afterCreate { item -> def SourcePath = RepoPathFactory.create('stage-release', item.repoPath.path) def DestPath = RepoPathFactory.create('release', item.repoPath.path) if (item.repoPath.repoKey == 'stage-release') { echo " ID is " + item.repoPath.id if (repositories.exists(DestPath)) { echo "FOUND the artifact in the release repo so no need to copy" } else { echo "MISSING artifact in the release repo so copying it over" // 添加参数禁用复制时的钩子触发 repositories.copy(SourcePath, DestPath, [suppressInterceptors: true]) } } } } def echo(str) { log.warn "########################### " + str; }
为什么升级后才出现问题?
Artifactory升级到5.5.1后,插件系统的钩子执行机制做了并发安全的强化校验——升级前可能没有这么严格的检测,所以钩子的循环触发没有抛出异常,但实际上这种写法本身就存在线程安全隐患,只是之前没暴露出来而已。
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

