fix(delete-brand): 分片缺失降级组装收尾+失败兜底生成可下载结果

- 结果分片缺失 ≤ missingChunkFallbackLimit(默认20) 时降级组装,缺失行标「未回传」,任务不再整体白跑
- 超阈值失败/组装异常时通过 ResultFileJobHandler.fallbackAssembleOnFailure 兜底生成部分结果文件
- 组装失败文案带缺失分片号明细(如 缺失分片: [247](已收 4283/4284))
- 新增 GET /api/delete-brand/tasks/{taskId}/missing-chunks,补传后自动恢复终态失败组装 job
- stale-check 失败文案改为含最后心跳时间与最近组装失败真实原因(修复误导性「回传长时间无响应」)
- 新增降级合并/缺失分片单测,Handler/Worker 日志审计 stage 白名单补 FALLBACK
This commit is contained in:
2026-09-08 13:18:17 +08:00
parent d9e3f34d37
commit f2906e8d6f
13 changed files with 581 additions and 15 deletions
@@ -10,6 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* DeleteBrandResultFileJobHandler 测试(任务 70)。
@@ -64,6 +65,16 @@ class DeleteBrandResultFileJobHandlerTest {
assertFalse(handler.isOwnerScoped());
}
@Test
void fallbackAssembleDelegates() {
TaskFileJobEntity job = new TaskFileJobEntity();
job.setTaskId(27171L);
job.setResultId(30195L);
when(deleteBrandRunService.fallbackAssembleResultFile(job)).thenReturn(true);
assertEquals(true, handler.fallbackAssembleOnFailure(job, "结果分片未完整"));
verify(deleteBrandRunService).fallbackAssembleResultFile(job);
}
@Test
void nullJobGuarded() {
assertTrue(handler.process(null));