fix(aigc): bind callback artifacts before completion

This commit is contained in:
lili 2026-07-23 00:45:25 -07:00
parent 3d928c4f8c
commit 68f8b4fa86
2 changed files with 32 additions and 0 deletions

View File

@ -8,6 +8,7 @@ import com.wanxiang.huijing.game.module.aigc.enums.FailureReasonEnum;
import com.wanxiang.huijing.game.module.aigc.service.task.AigcTaskService;
import com.wanxiang.huijing.game.module.aigc.service.task.ReadinessScorer;
import com.wanxiang.huijing.game.module.project.api.ProjectVersionApi;
import com.wanxiang.huijing.game.module.project.dto.ProjectVersionBindArtifactReqDTO;
import com.wanxiang.huijing.game.module.project.dto.ProjectVersionCreateForPackageReqDTO;
import com.wanxiang.huijing.game.module.runtime.api.RuntimePackageApi;
import com.wanxiang.huijing.game.module.runtime.dto.RuntimePackageStoreReqDTO;
@ -218,6 +219,15 @@ public class DifyCallbackTxService {
log.info("[handleCallbackTx] 落包完成 taskId={}, traceId={}, versionId={}, pkgId={}, checksum={}, bundleSize={}",
task.getId(), reqVO.getTraceId(), versionId, pkgId, packed.checksum(), packed.bundleSize());
// runtime 落包成功后在同一事务内把相同权威摘要绑定到版本失败会回滚并阻止任务完成
ProjectVersionBindArtifactReqDTO artifactReq = new ProjectVersionBindArtifactReqDTO();
artifactReq.setVersionId(versionId);
artifactReq.setChecksum(packed.checksum());
artifactReq.setBundleSize(packed.bundleSize());
projectVersionApi.bindRuntimeArtifact(artifactReq).getCheckedData();
log.info("[handleCallbackTx] 版本摘要绑定完成 taskId={}, traceId={}, versionId={}, checksum={}",
task.getId(), reqVO.getTraceId(), versionId, packed.checksum());
// ===== 步骤回填任务既有幂等 status=2 + version_id + progress 100 + finishTime =====
aigcTaskService.completeWithVersion(task.getId(), versionId);
log.info("[handleCallbackTx] 回调 succeeded 三表写入链完成 taskId={}, traceId={}, versionId={}",

View File

@ -7,6 +7,7 @@ import com.wanxiang.huijing.game.module.aigc.enums.AigcTaskStatusEnum;
import com.wanxiang.huijing.game.module.aigc.service.task.AigcTaskService;
import com.wanxiang.huijing.game.module.community.api.CommunityNotifyApi;
import com.wanxiang.huijing.game.module.project.api.ProjectVersionApi;
import com.wanxiang.huijing.game.module.project.dto.ProjectVersionBindArtifactReqDTO;
import com.wanxiang.huijing.game.module.project.dto.ProjectVersionCreateForPackageReqDTO;
import com.wanxiang.huijing.game.module.runtime.api.RuntimePackageApi;
import com.wanxiang.huijing.game.module.runtime.dto.RuntimePackageStoreReqDTO;
@ -95,6 +96,9 @@ class DifyCallbackServiceImplTest extends BaseMockitoUnitTest {
void setUpService() {
// MockitoExtension 已完成 @InjectMocks 注入此处组装外层构造器注入内层真实例
callbackService = new DifyCallbackServiceImpl(txService);
lenient().when(projectVersionApi.bindRuntimeArtifact(any(ProjectVersionBindArtifactReqDTO.class)))
.thenReturn(CommonResult.success(Boolean.TRUE));
}
// ============================== 用例1succeeded 全链 ==============================
@ -339,6 +343,24 @@ class DifyCallbackServiceImplTest extends BaseMockitoUnitTest {
assertEquals("llm_error", last.getFailureReason());
verify(aigcTaskService, never()).completeWithVersion(anyLong(), anyLong());
}
@Test
void testHandleCallback_bindRuntimeArtifactError_compensatesBeforeTaskCompletion() {
// runtime 落包成功但 project 摘要回写失败时必须向上抛错任务不得完成
when(aigcTaskMapper.selectByTraceId("aigc-trace-1")).thenAnswer(inv -> queuedTask());
when(projectVersionApi.createForPackage(any(ProjectVersionCreateForPackageReqDTO.class)))
.thenReturn(CommonResult.success(2048L));
when(runtimePackageApi.storeForVersion(any(RuntimePackageStoreReqDTO.class)))
.thenReturn(CommonResult.success(99L));
when(projectVersionApi.bindRuntimeArtifact(any(ProjectVersionBindArtifactReqDTO.class)))
.thenThrow(new ServiceException(1_100_000_008, "版本摘要绑定失败(模拟)"));
ServiceException ex = assertThrows(ServiceException.class,
() -> callbackService.handleCallback(succeededReq()));
assertEquals(1_100_000_008, ex.getCode());
verify(runtimePackageApi).storeForVersion(any(RuntimePackageStoreReqDTO.class));
verify(aigcTaskService, never()).completeWithVersion(anyLong(), anyLong());
}
// ============================== 用例10failureReason 非法 ==============================