You've already forked FrameTour-BE
feat(puzzle): 添加拼图素材版本缓存优化重复生成
- 新增 puzzleSourceVersionCache 缓存用于记录拼图素材版本 - 实现 isPuzzleSourceChanged 方法判断素材是否变化 - 添加 markPuzzleSourceVersion 方法标记当前素材版本 - 实现 invalidatePuzzleSourceVersion 方法清除指定人脸缓存 - 在人脸关系变更时自动清除相关拼图素材版本缓存 - 重构 AppPuzzleController 使用 PuzzleRepository 替代直接访问 Mapper - 添加生成记录缓存机制,包括按人脸ID和记录ID的缓存 - 实现素材版本缓存命中时复用历史记录功能 - 优化重复内容检测逻辑,添加缓存标记机制 - 在各种生成流程中添加缓存清除逻辑确保数据一致性
This commit is contained in:
@@ -2,6 +2,7 @@ package com.ycwl.basic.puzzle.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ycwl.basic.biz.FaceStatusManager;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
import com.ycwl.basic.puzzle.dto.PuzzleGenerateRequest;
|
||||
import com.ycwl.basic.puzzle.dto.PuzzleGenerateResponse;
|
||||
@@ -56,6 +57,7 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
private final PuzzleDuplicationDetector duplicationDetector;
|
||||
private final PrinterService printerService;
|
||||
private final PuzzleEdgeRenderTaskService puzzleEdgeRenderTaskService;
|
||||
private final FaceStatusManager faceStatusManager;
|
||||
|
||||
public PuzzleGenerateServiceImpl(
|
||||
PuzzleRepository puzzleRepository,
|
||||
@@ -65,7 +67,8 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
@Lazy ScenicRepository scenicRepository,
|
||||
@Lazy PuzzleDuplicationDetector duplicationDetector,
|
||||
@Lazy PrinterService printerService,
|
||||
PuzzleEdgeRenderTaskService puzzleEdgeRenderTaskService) {
|
||||
PuzzleEdgeRenderTaskService puzzleEdgeRenderTaskService,
|
||||
@Lazy FaceStatusManager faceStatusManager) {
|
||||
this.puzzleRepository = puzzleRepository;
|
||||
this.recordMapper = recordMapper;
|
||||
this.imageRenderer = imageRenderer;
|
||||
@@ -74,6 +77,7 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
this.duplicationDetector = duplicationDetector;
|
||||
this.printerService = printerService;
|
||||
this.puzzleEdgeRenderTaskService = puzzleEdgeRenderTaskService;
|
||||
this.faceStatusManager = faceStatusManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,6 +105,32 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
}
|
||||
Long resolvedScenicId = resolveScenicId(template, request.getScenicId());
|
||||
|
||||
// 2.5 素材版本缓存检查(减少数据库查询)
|
||||
// 如果缓存存在,说明自上次成功生成后素材没有变化,可以直接复用历史记录
|
||||
if (request.getFaceId() != null && !faceStatusManager.isPuzzleSourceChanged(request.getFaceId(), template.getId(), 0)) {
|
||||
PuzzleGenerationRecordEntity cachedRecord = recordMapper.findLatestSuccessByFaceAndTemplate(
|
||||
request.getFaceId(), template.getId());
|
||||
if (cachedRecord != null) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("素材版本缓存命中,复用历史记录: faceId={}, templateId={}, recordId={}, imageUrl={}, duration={}ms",
|
||||
request.getFaceId(), template.getId(), cachedRecord.getId(),
|
||||
cachedRecord.getResultImageUrl(), duration);
|
||||
return PuzzleGenerateResponse.success(
|
||||
cachedRecord.getResultImageUrl(),
|
||||
cachedRecord.getResultFileSize(),
|
||||
cachedRecord.getResultWidth(),
|
||||
cachedRecord.getResultHeight(),
|
||||
(int) duration,
|
||||
cachedRecord.getId(),
|
||||
true,
|
||||
cachedRecord.getId()
|
||||
);
|
||||
}
|
||||
// 缓存存在但记录被删除,继续执行正常流程
|
||||
log.debug("素材版本缓存存在但历史记录不存在,继续正常生成: faceId={}, templateId={}",
|
||||
request.getFaceId(), template.getId());
|
||||
}
|
||||
|
||||
// 3. 查询并排序元素
|
||||
List<PuzzleElementEntity> elements = puzzleRepository.getElementsByTemplateId(template.getId());
|
||||
if (elements.isEmpty()) {
|
||||
@@ -124,6 +154,10 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
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(),
|
||||
@@ -141,6 +175,9 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
record.setContentHash(contentHash);
|
||||
recordMapper.insert(record);
|
||||
|
||||
// 清除生成记录缓存(新记录插入后列表和数量都会变化)
|
||||
puzzleRepository.clearRecordCacheByFace(request.getFaceId());
|
||||
|
||||
// 8. 创建边缘渲染任务并等待完成
|
||||
Long taskId = puzzleEdgeRenderTaskService.createRenderTask(
|
||||
record,
|
||||
@@ -164,6 +201,11 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
log.info("同步拼图边缘渲染完成: recordId={}, taskId={}, imageUrl={}, duration={}ms",
|
||||
record.getId(), taskId, waitResult.getImageUrl(), duration);
|
||||
|
||||
// 标记素材版本缓存(成功生成后)
|
||||
if (request.getFaceId() != null) {
|
||||
faceStatusManager.markPuzzleSourceVersion(request.getFaceId(), template.getId(), 0);
|
||||
}
|
||||
|
||||
// 重新查询记录获取完整信息(边缘渲染回调已更新)
|
||||
PuzzleGenerationRecordEntity updatedRecord = recordMapper.getById(record.getId());
|
||||
if (updatedRecord != null && updatedRecord.getResultImageUrl() != null) {
|
||||
@@ -212,6 +254,23 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
}
|
||||
Long resolvedScenicId = resolveScenicId(template, request.getScenicId());
|
||||
|
||||
// 2.5 素材版本缓存检查(减少数据库查询)
|
||||
// 如果缓存存在,说明自上次成功生成后素材没有变化,可以直接复用历史记录
|
||||
if (request.getFaceId() != null && !faceStatusManager.isPuzzleSourceChanged(request.getFaceId(), template.getId(), 0)) {
|
||||
PuzzleGenerationRecordEntity cachedRecord = recordMapper.findLatestSuccessByFaceAndTemplate(
|
||||
request.getFaceId(), template.getId());
|
||||
if (cachedRecord != null) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("素材版本缓存命中,复用历史记录: faceId={}, templateId={}, recordId={}, imageUrl={}, duration={}ms",
|
||||
request.getFaceId(), template.getId(), cachedRecord.getId(),
|
||||
cachedRecord.getResultImageUrl(), duration);
|
||||
return cachedRecord.getId();
|
||||
}
|
||||
// 缓存存在但记录被删除,继续执行正常流程
|
||||
log.debug("素材版本缓存存在但历史记录不存在,继续正常生成: faceId={}, templateId={}",
|
||||
request.getFaceId(), template.getId());
|
||||
}
|
||||
|
||||
// 3. 查询并排序元素
|
||||
List<PuzzleElementEntity> elements = puzzleRepository.getElementsByTemplateId(template.getId());
|
||||
if (elements.isEmpty()) {
|
||||
@@ -235,6 +294,10 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
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 duplicateRecord.getId();
|
||||
}
|
||||
|
||||
@@ -243,6 +306,9 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
record.setContentHash(contentHash);
|
||||
recordMapper.insert(record);
|
||||
|
||||
// 清除生成记录缓存(新记录插入后列表和数量都会变化)
|
||||
puzzleRepository.clearRecordCacheByFace(request.getFaceId());
|
||||
|
||||
// 8. 创建边缘渲染任务
|
||||
Long taskId = puzzleEdgeRenderTaskService.createRenderTask(
|
||||
record,
|
||||
@@ -253,6 +319,8 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
request.getQuality()
|
||||
);
|
||||
|
||||
// 异步任务:在回调成功后标记缓存(由边缘渲染服务在成功回调中处理)
|
||||
// 这里只记录请求信息供后续使用
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("异步拼图任务已进入边缘渲染队列: recordId={}, taskId={}, templateCode={}, duration={}ms",
|
||||
record.getId(), taskId, request.getTemplateCode(), duration);
|
||||
@@ -331,6 +399,9 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
record.setContentHash(contentHash);
|
||||
recordMapper.insert(record);
|
||||
|
||||
// 清除生成记录缓存(新记录插入后列表和数量都会变化)
|
||||
puzzleRepository.clearRecordCacheByFace(request.getFaceId());
|
||||
|
||||
// 9. 执行核心生成逻辑
|
||||
return doGenerateInternal(request, template, resolvedScenicId, record, startTime);
|
||||
}
|
||||
@@ -417,6 +488,9 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
(int) duration
|
||||
);
|
||||
|
||||
// 清除生成记录缓存(状态已更新)
|
||||
puzzleRepository.clearRecordCache(record.getId(), request.getFaceId());
|
||||
|
||||
log.info("拼图生成成功: recordId={}, originalUrl={}, finalUrl={}, duration={}ms",
|
||||
record.getId(), originalImageUrl, finalImageUrl, duration);
|
||||
|
||||
@@ -450,6 +524,8 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
|
||||
} catch (Exception e) {
|
||||
log.error("拼图生成失败: templateCode={}", request.getTemplateCode(), e);
|
||||
recordMapper.updateFail(record.getId(), e.getMessage());
|
||||
// 清除生成记录缓存(状态已更新)
|
||||
puzzleRepository.clearRecordCache(record.getId(), request.getFaceId());
|
||||
throw new RuntimeException("图片生成失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user