refactor(orchestrator): 优化人脸匹配拼图模板生成逻辑

- 引入线程同步机制确保打印机场景下拼图模板生成完成
- 修改 asyncGeneratePuzzleTemplate 方法返回 Thread 对象便于控制
- 使用虚拟线程池优化拼图模板并发生成性能
- 简化原子计数器和异步任务相关代码实现
- 添加线程 join 等待确保关键场景执行顺序
- 修复方法返回值类型和资源管理相关问题
This commit is contained in:
2025-12-31 19:50:18 +08:00
parent 91160a1adb
commit 5a61432dc9
2 changed files with 26 additions and 12 deletions

View File

@@ -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;
} }
/** /**

View File

@@ -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);
} }