fix(pipeline): 增加防御性检查避免空指针异常

- 在多个阶段中增加对 memberSourceList 和 searchResult 的空值检查
- 当 memberSourceList 为空时跳过视频重切和购买状态处理逻辑
- 当 searchResult 为空时跳过人脸补救逻辑
- 增加对自定义匹配场景的判断,非该场景则跳过指标记录
- 为各个阶段添加详细的单元测试覆盖各种边界条件
This commit is contained in:
2025-12-03 19:23:54 +08:00
parent 8c08c8947e
commit ecd5378b26
13 changed files with 1760 additions and 0 deletions

View File

@@ -54,6 +54,12 @@ public class FaceRecoveryStage extends AbstractFaceMatchingStage<FaceMatchingCon
SearchFaceRespVo searchResult = context.getSearchResult();
Long faceId = context.getFaceId();
// 防御性检查:searchResult为空
if (searchResult == null) {
log.debug("searchResult为空,跳过补救逻辑,faceId={}", faceId);
return StageResult.skipped("searchResult为空");
}
try {
// 执行补救逻辑(补救逻辑内部会判断是否需要触发)
SearchFaceRespVo recoveredResult = faceRecoveryStrategy.executeFaceRecoveryLogic(

View File

@@ -62,6 +62,12 @@ public class HandleVideoRecreationStage extends AbstractFaceMatchingStage<FaceMa
List<Long> sampleListIds = context.getSampleListIds();
boolean isNew = context.isNew();
// 防御性检查:memberSourceList为空
if (memberSourceEntityList == null || memberSourceEntityList.isEmpty()) {
log.debug("memberSourceList为空,跳过视频重切,faceId={}", faceId);
return StageResult.skipped("memberSourceList为空");
}
try {
// 处理视频重切
videoRecreationHandler.handleVideoRecreation(

View File

@@ -62,6 +62,12 @@ public class ProcessBuyStatusStage extends AbstractFaceMatchingStage<FaceMatchin
Long scenicId = context.getFace().getScenicId();
Long faceId = context.getFaceId();
// 防御性检查:memberSourceList为空
if (memberSourceEntityList == null || memberSourceEntityList.isEmpty()) {
log.debug("memberSourceList为空,跳过购买状态处理,faceId={}", faceId);
return StageResult.skipped("memberSourceList为空");
}
try {
// 处理购买状态
buyStatusProcessor.processBuyStatus(

View File

@@ -61,6 +61,12 @@ public class ProcessFreeSourceStage extends AbstractFaceMatchingStage<FaceMatchi
boolean isNew = context.isNew();
Long faceId = context.getFaceId();
// 防御性检查:memberSourceList为空
if (memberSourceEntityList == null || memberSourceEntityList.isEmpty()) {
log.debug("memberSourceList为空,跳过免费逻辑,faceId={}", faceId);
return StageResult.skipped("memberSourceList为空");
}
try {
// 处理免费逻辑
List<Long> freeSourceIds = sourceRelationProcessor.processFreeSourceLogic(

View File

@@ -51,6 +51,12 @@ public class RecordCustomMatchMetricsStage extends AbstractFaceMatchingStage<Fac
protected StageResult<FaceMatchingContext> doExecute(FaceMatchingContext context) {
Long faceId = context.getFaceId();
// 防御性检查:只有自定义匹配场景才执行
if (context.getScene() != FaceMatchingScene.CUSTOM_MATCHING) {
log.debug("非自定义匹配场景,跳过记录,faceId={}", faceId);
return StageResult.skipped("非自定义匹配场景");
}
try {
metricsRecorder.recordCustomMatchCount(faceId);
log.debug("记录自定义匹配次数: faceId={}", faceId);