You've already forked FrameTour-BE
refactor(orchestrator): 优化人脸匹配拼图模板生成逻辑
- 引入线程同步机制确保打印机场景下拼图模板生成完成 - 修改 asyncGeneratePuzzleTemplate 方法返回 Thread 对象便于控制 - 使用虚拟线程池优化拼图模板并发生成性能 - 简化原子计数器和异步任务相关代码实现 - 添加线程 join 等待确保关键场景执行顺序 - 修复方法返回值类型和资源管理相关问题
This commit is contained in:
@@ -33,6 +33,7 @@ import com.ycwl.basic.service.pc.processor.VideoRecreationHandler;
|
|||||||
import com.ycwl.basic.service.task.TaskFaceService;
|
import com.ycwl.basic.service.task.TaskFaceService;
|
||||||
import com.ycwl.basic.service.task.TaskService;
|
import com.ycwl.basic.service.task.TaskService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.Strings;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -40,7 +41,11 @@ import org.springframework.stereotype.Component;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,7 +151,12 @@ public class FaceMatchingOrchestrator {
|
|||||||
processSourceRelations(context, searchResult, faceId, isNew);
|
processSourceRelations(context, searchResult, faceId, isNew);
|
||||||
|
|
||||||
// 步骤7: 异步生成拼图模板
|
// 步骤7: 异步生成拼图模板
|
||||||
asyncGeneratePuzzleTemplate(context.face.getScenicId(), faceId, context.face.getMemberId());
|
Thread thread = asyncGeneratePuzzleTemplate(context.face.getScenicId(), faceId, context.face.getMemberId());
|
||||||
|
if (Strings.CI.equals(scene, "printer")) {
|
||||||
|
if (thread != null) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return searchResult;
|
return searchResult;
|
||||||
|
|
||||||
@@ -354,16 +364,18 @@ public class FaceMatchingOrchestrator {
|
|||||||
/**
|
/**
|
||||||
* 步骤8: 异步生成拼图模板
|
* 步骤8: 异步生成拼图模板
|
||||||
* 在人脸匹配完成后,异步为该景区的所有启用的拼图模板生成图片
|
* 在人脸匹配完成后,异步为该景区的所有启用的拼图模板生成图片
|
||||||
|
*
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
private void asyncGeneratePuzzleTemplate(Long scenicId, Long faceId, Long memberId) {
|
private Thread asyncGeneratePuzzleTemplate(Long scenicId, Long faceId, Long memberId) {
|
||||||
if (redisTemplate.hasKey("puzzle_generated:face:" + faceId)) {
|
if (redisTemplate.hasKey("puzzle_generated:face:" + faceId)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
redisTemplate.opsForValue().set(
|
redisTemplate.opsForValue().set(
|
||||||
"puzzle_generated:face:" + faceId,
|
"puzzle_generated:face:" + faceId,
|
||||||
"1",
|
"1",
|
||||||
60 * 10, TimeUnit.SECONDS);
|
60 * 10, TimeUnit.SECONDS);
|
||||||
new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
log.info("开始异步生成景区拼图模板: scenicId={}, faceId={}", scenicId, faceId);
|
log.info("开始异步生成景区拼图模板: scenicId={}, faceId={}", scenicId, faceId);
|
||||||
|
|
||||||
@@ -398,13 +410,13 @@ public class FaceMatchingOrchestrator {
|
|||||||
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd"));
|
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd"));
|
||||||
|
|
||||||
// 使用虚拟线程池并行生成所有模板
|
// 使用虚拟线程池并行生成所有模板
|
||||||
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
AtomicInteger successCount = new AtomicInteger(0);
|
||||||
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
AtomicInteger failCount = new AtomicInteger(0);
|
||||||
|
|
||||||
try (java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
|
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
||||||
// 为每个模板创建一个异步任务
|
// 为每个模板创建一个异步任务
|
||||||
List<java.util.concurrent.CompletableFuture<Void>> futures = templateList.stream()
|
List<CompletableFuture<Void>> futures = templateList.stream()
|
||||||
.map(template -> java.util.concurrent.CompletableFuture.runAsync(() -> {
|
.map(template -> CompletableFuture.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
|
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
|
||||||
scenicId, template.getCode(), template.getName());
|
scenicId, template.getCode(), template.getName());
|
||||||
@@ -437,7 +449,7 @@ public class FaceMatchingOrchestrator {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
// 等待所有任务完成
|
// 等待所有任务完成
|
||||||
java.util.concurrent.CompletableFuture.allOf(futures.toArray(new java.util.concurrent.CompletableFuture[0])).join();
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
|
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
|
||||||
@@ -447,7 +459,9 @@ public class FaceMatchingOrchestrator {
|
|||||||
// 异步任务失败不影响主流程,仅记录日志
|
// 异步任务失败不影响主流程,仅记录日志
|
||||||
log.error("异步生成拼图模板失败: scenicId={}, faceId={}", scenicId, faceId, e);
|
log.error("异步生成拼图模板失败: scenicId={}, faceId={}", scenicId, faceId, e);
|
||||||
}
|
}
|
||||||
}, "PuzzleTemplateGenerator-" + scenicId).start();
|
}, "PuzzleTemplateGenerator-" + scenicId);
|
||||||
|
thread.start();
|
||||||
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1244,7 +1244,7 @@ public class PrinterServiceImpl implements PrinterService {
|
|||||||
resp.setFaceId(faceId);
|
resp.setFaceId(faceId);
|
||||||
resp.setScenicId(scenicId);
|
resp.setScenicId(scenicId);
|
||||||
try {
|
try {
|
||||||
faceService.matchFaceId(faceId);
|
faceService.matchFaceId(faceId, true, "printer");
|
||||||
if (existingFace == null) {
|
if (existingFace == null) {
|
||||||
autoAddPhotosToPreferPrint(faceId);
|
autoAddPhotosToPreferPrint(faceId);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user