refactor(similar-asin): 抽出 LlmPipelineSupport,Service 降至 1735 行(累计 -70.7%)

在上一提交(3455 行)基础上,把「Python 结果回传 → 分片落库 → LLM 检测」整条流水线
(57 个方法 / 1694 行)抽为 SimilarAsinPipelineSupport。等价搬移,未改行为。

采用依赖倒置消除循环依赖:support 包声明 SimilarAsinPipelineHost 接口
(finalizeTask / findOrCreateResultRecordForAssembly / readCategorySwitch /
finalizeExhaustedResultFileJob),由 SimilarAsinTaskService 实现;这几项保留在宿主
是因为它们属于编排与事务边界(handleResultFileJobFailure 带 @Transactional)。

同时把 5 个被两侧共用的内部 record 提为 support 包顶层类型
(SubmittedTaskMetadata / FinalizeTaskResult / SubmitContext /
 PersistSubmittedChunkResult / PreparedSubmittedChunk),3 个仅流水线内部使用的
record 内联进流水线类;LlmBatchContext 一并归位。

测试适配:4 个测试类里对 mergeLlmRowsIntoChunk / bufferLlmRowsOrMerge /
flushLlmBufferedResults 的反射改指向流水线实例;RollbackSemanticsContractTest
通过 pipelineSupport() 反射取得实例(跨包,保持封装)。

验证:干净工作区叠加本改动跑 similarasin 386 + task 引用方 166 测试,
结果与基线一致(仅既有失败),零新增失败。
This commit is contained in:
2026-09-14 01:51:36 +08:00
parent 9d92fb4af2
commit b05bba50fa
13 changed files with 2105 additions and 1810 deletions
@@ -0,0 +1,9 @@
package com.nanri.aiimage.modules.similarasin.service.support;
/**
* 任务收尾结果:taskId 与是否已达终态。
* spec 05 续(拆分第 7 轮):从 SimilarAsinTaskService 原样搬出为顶层 record。
*/
public record FinalizeTaskResult(Long taskId,
boolean terminal) {
}
@@ -0,0 +1,10 @@
package com.nanri.aiimage.modules.similarasin.service.support;
/**
* 分片落库结果:提交上下文、payload 是否落库、以及收尾结果。
* spec 05 续(拆分第 7 轮):从 SimilarAsinTaskService 原样搬出为顶层 record。
*/
public record PersistSubmittedChunkResult(SubmitContext context,
boolean payloadPersisted,
FinalizeTaskResult finalizeResult) {
}
@@ -0,0 +1,19 @@
package com.nanri.aiimage.modules.similarasin.service.support;
/**
* 预处理后的待落库分片:行裁剪/校验后的最小写入单元。
* spec 05 续(拆分第 7 轮):从 SimilarAsinTaskService 原样搬出为顶层 record。
*/
public record PreparedSubmittedChunk(Long taskId,
String scopeKey,
String scopeHash,
Integer chunkIndex,
Integer chunkTotal,
boolean done,
String error,
String payloadJson,
String storedPayload,
boolean localFallback,
SubmittedTaskMetadata taskMetadata,
String payloadHash) {
}
@@ -0,0 +1,31 @@
package com.nanri.aiimage.modules.similarasin.service.support;
import com.nanri.aiimage.modules.task.model.entity.FileResultEntity;
import com.nanri.aiimage.modules.task.model.entity.FileTaskEntity;
import com.nanri.aiimage.modules.task.model.entity.TaskFileJobEntity;
/**
* spec 05 续(拆分第 7 轮):Python 回传 → 分片落库 → LLM 检测流水线需要宿主服务提供的能力。
* <p>
* 采用依赖倒置:由宿主(SimilarAsinTaskService)实现本接口,流水线只依赖接口,
* 避免 support 包与 Service 之间形成循环依赖。这些方法保留在宿主的两个原因:
* 一是属于任务/结果文件任务的编排与事务边界({@code handleResultFileJobFailure} 带 @Transactional),
* 二是被宿主自身的门面路径复用。
*/
public interface SimilarAsinPipelineHost {
/** 任务收尾状态机(成功/失败判定、结果文件装配入队、任务状态落库)。 */
FinalizeTaskResult finalizeTask(FileTaskEntity task,
String error,
SubmittedTaskMetadata taskMetadata,
boolean assembleWorkbook);
/** 取回或创建结果文件记录(用于装配阶段回填)。 */
FileResultEntity findOrCreateResultRecordForAssembly(FileTaskEntity task, int rowCount);
/** 读取任务的类目重试开关。 */
boolean readCategorySwitch(FileTaskEntity task);
/** 结果文件任务重试耗尽后的失败处理(宿主侧带事务边界)。 */
void finalizeExhaustedResultFileJob(TaskFileJobEntity job, String message);
}
@@ -0,0 +1,16 @@
package com.nanri.aiimage.modules.similarasin.service.support;
import com.nanri.aiimage.modules.task.model.entity.FileTaskEntity;
/**
* 一次 Python 结果提交的上下文。
* spec 05 续(拆分第 7 轮):从 SimilarAsinTaskService 原样搬出为顶层 record。
*/
public record SubmitContext(FileTaskEntity task,
String scopeKey,
String scopeHash,
Integer chunkIndex,
boolean forceFlush,
String error,
SubmittedTaskMetadata taskMetadata) {
}
@@ -0,0 +1,14 @@
package com.nanri.aiimage.modules.similarasin.service.support;
import com.nanri.aiimage.modules.similarasin.model.dto.SimilarAsinSourceFileDto;
import java.util.List;
/**
* 提交阶段的任务元信息:总行数与源文件清单。
* spec 05 续(拆分第 7 轮):从 SimilarAsinTaskService 原样搬出为顶层 record
* 供流水线与其宿主服务共用。
*/
public record SubmittedTaskMetadata(int rowCount,
List<SimilarAsinSourceFileDto> sourceFiles) {
}