From 4ac59b1f31b9c3fa6c788dabd985305a9d180fa4 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 14 Feb 2026 01:58:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(puzzle):=20=E8=A7=A3=E5=86=B3=E6=8B=BC?= =?UTF-8?q?=E5=9B=BE=E7=94=9F=E6=88=90=E6=9C=8D=E5=8A=A1=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E6=A3=80=E6=B5=8B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加对正在生成中记录的状态检查,避免并发重复写入 - 实现等待机制处理相同内容正在生成的情况 - 优化数据库查询逻辑,同时匹配成功和生成中的记录 - 仅对成功记录标记素材版本缓存,避免生成中记录失败时的错误标记 - 更新日志输出包含记录状态信息以便调试 - 添加超时机制确保系统稳定性 --- .../impl/PuzzleGenerateServiceImpl.java | 94 +++++++++++++++---- .../mapper/PuzzleGenerationRecordMapper.xml | 6 +- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java b/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java index c7e7fd85..26c07596 100644 --- a/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java +++ b/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java @@ -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; + } + /** * 校验请求参数 */ diff --git a/src/main/resources/mapper/PuzzleGenerationRecordMapper.xml b/src/main/resources/mapper/PuzzleGenerationRecordMapper.xml index db944984..035455a5 100644 --- a/src/main/resources/mapper/PuzzleGenerationRecordMapper.xml +++ b/src/main/resources/mapper/PuzzleGenerationRecordMapper.xml @@ -128,15 +128,15 @@ WHERE id = #{id} - +