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.TaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@@ -40,7 +41,11 @@ import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
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.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
@@ -146,7 +151,12 @@ public class FaceMatchingOrchestrator {
processSourceRelations(context, searchResult, faceId, isNew);
// 步骤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;
@@ -354,16 +364,18 @@ public class FaceMatchingOrchestrator {
/**
* 步骤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)) {
return;
return null;
}
redisTemplate.opsForValue().set(
"puzzle_generated:face:" + faceId,
"1",
60 * 10, TimeUnit.SECONDS);
new Thread(() -> {
Thread thread = new Thread(() -> {
try {
log.info("开始异步生成景区拼图模板: scenicId={}, faceId={}", scenicId, faceId);
@@ -398,13 +410,13 @@ public class FaceMatchingOrchestrator {
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd"));
// 使用虚拟线程池并行生成所有模板
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
AtomicInteger successCount = new 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()
.map(template -> java.util.concurrent.CompletableFuture.runAsync(() -> {
List<CompletableFuture<Void>> futures = templateList.stream()
.map(template -> CompletableFuture.runAsync(() -> {
try {
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
scenicId, template.getCode(), template.getName());
@@ -437,7 +449,7 @@ public class FaceMatchingOrchestrator {
.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={}, 总数={}, 成功={}, 失败={}",
@@ -447,7 +459,9 @@ public class FaceMatchingOrchestrator {
// 异步任务失败不影响主流程,仅记录日志
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.setScenicId(scenicId);
try {
faceService.matchFaceId(faceId);
faceService.matchFaceId(faceId, true, "printer");
if (existingFace == null) {
autoAddPhotosToPreferPrint(faceId);
}