增加生成后端服务代码。

This commit is contained in:
dengqichen 2025-10-25 17:04:28 +08:00
parent 07db17faf6
commit d30614c857
2 changed files with 112 additions and 22 deletions

View File

@ -65,36 +65,126 @@ public class RepositoryBranchServiceImpl extends BaseServiceImpl<RepositoryBranc
@Resource(name = "repositoryBranchExecutor") @Resource(name = "repositoryBranchExecutor")
private ThreadPoolTaskExecutor executor; private ThreadPoolTaskExecutor executor;
private static final int BATCH_SIZE = 100; private static final int BATCH_SIZE = 50; // 减小批次大小提高容错性
private static final int MAX_RETRIES = 3; private static final int MAX_RETRIES = 3;
private static final long RETRY_DELAY = 100L; private static final long RETRY_DELAY = 100L;
private static final int MAX_WEB_URL_LENGTH = 1000; // web_url 字段最大长度
/**
* 批量保存分支优化版
* 1. 分批保存减少单次事务大小
* 2. 单条记录失败不影响其他记录
* 3. 支持乐观锁重试
*/
@Transactional @Transactional
public void saveBatch(List<RepositoryBranch> branches) { public void saveBatch(List<RepositoryBranch> branches) {
int retryCount = 0; if (branches == null || branches.isEmpty()) {
while (retryCount < MAX_RETRIES) { return;
try { }
for (int i = 0; i < branches.size(); i += BATCH_SIZE) {
int end = Math.min(i + BATCH_SIZE, branches.size()); log.info("开始批量保存 {} 条分支记录", branches.size());
List<RepositoryBranch> batch = branches.subList(i, end); int successCount = 0;
repositoryBranchRepository.saveAll(batch); int failureCount = 0;
} List<String> failedBranches = new ArrayList<>();
return;
} catch (ObjectOptimisticLockingFailureException e) { // 分批处理
retryCount++; for (int i = 0; i < branches.size(); i += BATCH_SIZE) {
if (retryCount >= MAX_RETRIES) { int end = Math.min(i + BATCH_SIZE, branches.size());
throw e; List<RepositoryBranch> batch = branches.subList(i, end);
}
log.warn("Optimistic locking failure during batch save, retry attempt {}", retryCount); // 批次内逐条保存避免一条失败导致整批失败
try { for (RepositoryBranch branch : batch) {
Thread.sleep(RETRY_DELAY * retryCount); int retryCount = 0;
} catch (InterruptedException ie) { boolean saved = false;
Thread.currentThread().interrupt();
throw new RuntimeException("Interrupted during retry delay", ie); while (retryCount <= MAX_RETRIES && !saved) {
try {
// 数据清洗截断过长的字段
sanitizeBranchData(branch);
// 保存单条记录
repositoryBranchRepository.save(branch);
successCount++;
saved = true;
if (retryCount > 0) {
log.info("分支 {} 重试第 {} 次成功", branch.getName(), retryCount);
}
} catch (ObjectOptimisticLockingFailureException e) {
// 乐观锁冲突重试
retryCount++;
if (retryCount > MAX_RETRIES) {
failureCount++;
String errorMsg = String.format("%s (乐观锁冲突)", branch.getName());
failedBranches.add(errorMsg);
log.error("分支 {} 保存失败,乐观锁冲突重试 {} 次后仍失败", branch.getName(), MAX_RETRIES, e);
} else {
log.warn("分支 {} 乐观锁冲突,进行第 {} 次重试", branch.getName(), retryCount);
try {
Thread.sleep(RETRY_DELAY * retryCount);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
log.error("重试延迟被中断", ie);
}
}
} catch (Exception e) {
// 其他异常如数据过长约束冲突等记录日志并跳过
failureCount++;
String errorMsg = String.format("%s (%s)", branch.getName(), e.getMessage());
failedBranches.add(errorMsg);
log.error("分支 {} 保存失败: {}, webUrl长度={}",
branch.getName(),
e.getMessage(),
branch.getWebUrl() != null ? branch.getWebUrl().length() : 0,
e);
break; // 非乐观锁异常不重试
}
} }
} }
log.info("批次 [{}-{}] 保存完成,成功: {}, 失败: {}",
i, end - 1, successCount, failureCount);
}
// 汇总结果
log.info("批量保存完成 - 总数: {}, 成功: {}, 失败: {}",
branches.size(), successCount, failureCount);
if (!failedBranches.isEmpty()) {
log.warn("保存失败的分支列表前10条: {}",
failedBranches.stream().limit(10).collect(Collectors.toList()));
}
// 如果全部失败抛出异常
if (failureCount == branches.size() && branches.size() > 0) {
throw new BusinessException(ResponseCode.REPOSITORY_BRANCH_SYNC_FAILED,
new Object[]{"所有分支保存失败"});
}
}
/**
* 数据清洗截断过长的字段避免数据库插入失败
*/
private void sanitizeBranchData(RepositoryBranch branch) {
// 截断 web_url
if (branch.getWebUrl() != null && branch.getWebUrl().length() > MAX_WEB_URL_LENGTH) {
String original = branch.getWebUrl();
branch.setWebUrl(original.substring(0, MAX_WEB_URL_LENGTH));
log.warn("分支 {} 的 web_url 超长({}字符),已截断至 {} 字符",
branch.getName(), original.length(), MAX_WEB_URL_LENGTH);
}
// 截断 commit_messageTEXT 类型通常足够大但防御性处理
if (branch.getCommitMessage() != null && branch.getCommitMessage().length() > 5000) {
branch.setCommitMessage(branch.getCommitMessage().substring(0, 5000) + "...");
}
// 截断 commit_author
if (branch.getCommitAuthor() != null && branch.getCommitAuthor().length() > 100) {
branch.setCommitAuthor(branch.getCommitAuthor().substring(0, 100));
} }
} }

View File

@ -353,7 +353,7 @@ CREATE TABLE deploy_repo_branch
commit_date DATETIME(6) NULL COMMENT '最新提交时间', commit_date DATETIME(6) NULL COMMENT '最新提交时间',
last_update_time DATETIME(6) NULL COMMENT '分支最后更新时间', last_update_time DATETIME(6) NULL COMMENT '分支最后更新时间',
last_commit_time DATETIME(6) NULL COMMENT '分支最后提交时间', last_commit_time DATETIME(6) NULL COMMENT '分支最后提交时间',
web_url VARCHAR(255) NULL COMMENT '网页URL', web_url VARCHAR(1000) NULL COMMENT '网页URL',
project_id BIGINT NOT NULL COMMENT '所属项目ID', project_id BIGINT NOT NULL COMMENT '所属项目ID',
external_system_id BIGINT NOT NULL COMMENT '外部系统ID', external_system_id BIGINT NOT NULL COMMENT '外部系统ID',
repo_project_id BIGINT NOT NULL COMMENT 'GitLab的真实project_id', repo_project_id BIGINT NOT NULL COMMENT 'GitLab的真实project_id',