You've already forked FrameTour-BE
fix(puzzle): 解决拼图生成服务重复内容检测问题
- 添加对正在生成中记录的状态检查,避免并发重复写入 - 实现等待机制处理相同内容正在生成的情况 - 优化数据库查询逻辑,同时匹配成功和生成中的记录 - 仅对成功记录标记素材版本缓存,避免生成中记录失败时的错误标记 - 更新日志输出包含记录状态信息以便调试 - 添加超时机制确保系统稳定性
This commit is contained in:
@@ -141,23 +141,50 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
template.getId(), contentHash, resolvedScenicId
|
||||
);
|
||||
if (duplicateRecord != null) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("检测到重复内容,复用历史记录: recordId={}, imageUrl={}, duration={}ms",
|
||||
duplicateRecord.getId(), duplicateRecord.getResultImageUrl(), duration);
|
||||
// 标记素材版本缓存
|
||||
if (request.getFaceId() != null) {
|
||||
faceStatusManager.markPuzzleSourceVersion(request.getFaceId(), template.getId(), 0);
|
||||
if (duplicateRecord.getStatus() == 1) {
|
||||
// 已有成功记录,直接复用
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("检测到重复内容,复用历史记录: recordId={}, imageUrl={}, duration={}ms",
|
||||
duplicateRecord.getId(), duplicateRecord.getResultImageUrl(), duration);
|
||||
// 标记素材版本缓存
|
||||
if (request.getFaceId() != null) {
|
||||
faceStatusManager.markPuzzleSourceVersion(request.getFaceId(), template.getId(), 0);
|
||||
}
|
||||
return PuzzleGenerateResponse.success(
|
||||
duplicateRecord.getResultImageUrl(),
|
||||
duplicateRecord.getResultFileSize(),
|
||||
duplicateRecord.getResultWidth(),
|
||||
duplicateRecord.getResultHeight(),
|
||||
(int) duration,
|
||||
duplicateRecord.getId(),
|
||||
true,
|
||||
duplicateRecord.getId()
|
||||
);
|
||||
} else if (duplicateRecord.getStatus() == 0) {
|
||||
// 相同内容正在生成中,等待完成后复用
|
||||
log.info("检测到相同内容正在生成中,等待完成: recordId={}", duplicateRecord.getId());
|
||||
PuzzleGenerationRecordEntity completedRecord = waitForRecordCompletion(duplicateRecord.getId(), 30_000);
|
||||
if (completedRecord != null && completedRecord.getStatus() == 1) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("等待生成中记录完成,复用结果: recordId={}, imageUrl={}, duration={}ms",
|
||||
completedRecord.getId(), completedRecord.getResultImageUrl(), duration);
|
||||
if (request.getFaceId() != null) {
|
||||
faceStatusManager.markPuzzleSourceVersion(request.getFaceId(), template.getId(), 0);
|
||||
}
|
||||
return PuzzleGenerateResponse.success(
|
||||
completedRecord.getResultImageUrl(),
|
||||
completedRecord.getResultFileSize(),
|
||||
completedRecord.getResultWidth(),
|
||||
completedRecord.getResultHeight(),
|
||||
(int) duration,
|
||||
completedRecord.getId(),
|
||||
true,
|
||||
completedRecord.getId()
|
||||
);
|
||||
}
|
||||
// 超时或失败,兜底创建新记录
|
||||
log.warn("等待生成中记录超时或失败,创建新记录: originalRecordId={}", duplicateRecord.getId());
|
||||
}
|
||||
return PuzzleGenerateResponse.success(
|
||||
duplicateRecord.getResultImageUrl(),
|
||||
duplicateRecord.getResultFileSize(),
|
||||
duplicateRecord.getResultWidth(),
|
||||
duplicateRecord.getResultHeight(),
|
||||
(int) duration,
|
||||
duplicateRecord.getId(),
|
||||
true,
|
||||
duplicateRecord.getId()
|
||||
);
|
||||
}
|
||||
|
||||
// 7. 创建生成记录
|
||||
@@ -290,10 +317,10 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
);
|
||||
if (duplicateRecord != null) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("检测到重复内容,复用历史记录: recordId={}, imageUrl={}, duration={}ms",
|
||||
duplicateRecord.getId(), duplicateRecord.getResultImageUrl(), duration);
|
||||
// 标记素材版本缓存
|
||||
if (request.getFaceId() != null) {
|
||||
log.info("检测到重复内容,复用历史记录: recordId={}, status={}, imageUrl={}, duration={}ms",
|
||||
duplicateRecord.getId(), duplicateRecord.getStatus(), duplicateRecord.getResultImageUrl(), duration);
|
||||
// 仅成功记录才标记素材版本缓存(生成中的记录可能会失败)
|
||||
if (request.getFaceId() != null && duplicateRecord.getStatus() == 1) {
|
||||
faceStatusManager.markPuzzleSourceVersion(request.getFaceId(), template.getId(), 0);
|
||||
}
|
||||
return duplicateRecord.getId();
|
||||
@@ -326,6 +353,33 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待生成中的记录完成
|
||||
* 轮询数据库直到记录状态变为非生成中(成功或失败),或超时返回null
|
||||
*
|
||||
* @param recordId 记录ID
|
||||
* @param timeoutMs 超时时间(毫秒)
|
||||
* @return 完成后的记录,超时返回null
|
||||
*/
|
||||
private PuzzleGenerationRecordEntity waitForRecordCompletion(Long recordId, long timeoutMs) {
|
||||
long deadline = System.currentTimeMillis() + timeoutMs;
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
PuzzleGenerationRecordEntity record = recordMapper.getById(recordId);
|
||||
if (record == null || record.getStatus() != 0) {
|
||||
return record;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.warn("等待记录完成被中断: recordId={}", recordId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
log.warn("等待记录完成超时: recordId={}, timeoutMs={}", recordId, timeoutMs);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验请求参数
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user