task-129: shopdatacrawl 事务收缩(/result 无长事务契约固化 + deleteTask 纯计算抽静态纯函数)+ 8 条边界测试

This commit is contained in:
2026-09-02 04:15:44 +08:00
parent ecc62f095b
commit 5e71e1bb3d
2 changed files with 340 additions and 8 deletions
@@ -686,19 +686,13 @@ public class ShopDataCrawlTaskService {
List<FileResultEntity> taskRows = listTaskRows(taskId);
try (DailyLockSet dailyLocks = acquireDailyLocks(taskRows)) {
ensureDailySyncCompletedBeforeDelete(taskRows);
Set<Long> removedResultIds = taskRows.stream()
.map(FileResultEntity::getId)
.filter(id -> id != null && id > 0)
.collect(java.util.stream.Collectors.toSet());
Set<Long> removedResultIds = collectResultIds(taskRows);
// A task deletion is only a frontend task-record cleanup. The daily
// workbook is an independent backend aggregate and must not roll
// back when its source task is removed.
DailyDeletionResult dailyResult = preserveDailyForTaskDeletion(removedResultIds);
registerUploadedObjectRollback(dailyResult.uploadedObjectKeys());
List<String> resultFileUrls = new ArrayList<>(dailyResult.obsoleteObjectKeys());
resultFileUrls.addAll(taskRows.stream()
.map(FileResultEntity::getResultFileUrl).filter(url -> !blank(url)).distinct().toList());
resultFileUrls = resultFileUrls.stream().filter(url -> !blank(url)).distinct().toList();
List<String> resultFileUrls = collectResultFileUrls(taskRows, dailyResult.obsoleteObjectKeys());
fileResultMapper.delete(new LambdaQueryWrapper<FileResultEntity>()
.eq(FileResultEntity::getTaskId, taskId)
.eq(FileResultEntity::getModuleType, MODULE_TYPE));
@@ -713,6 +707,32 @@ public class ShopDataCrawlTaskService {
}
}
/** 删除任务的纯计算:收集有效结果行 id 集合(过滤 null/非正数),无副作用。 */
static Set<Long> collectResultIds(List<FileResultEntity> taskRows) {
if (taskRows == null || taskRows.isEmpty()) {
return Set.of();
}
return taskRows.stream()
.filter(Objects::nonNull)
.map(FileResultEntity::getId)
.filter(id -> id != null && id > 0)
.collect(java.util.stream.Collectors.toSet());
}
/** 删除任务的纯计算:合并待清理对象键,过滤空白并去重,无副作用。 */
static List<String> collectResultFileUrls(List<FileResultEntity> taskRows, List<String> obsoleteObjectKeys) {
List<String> urls = new ArrayList<>(obsoleteObjectKeys == null ? List.of() : obsoleteObjectKeys);
if (taskRows != null) {
for (FileResultEntity row : taskRows) {
if (row == null || row.getResultFileUrl() == null || row.getResultFileUrl().isBlank()) {
continue;
}
urls.add(row.getResultFileUrl());
}
}
return urls.stream().filter(url -> url != null && !url.isBlank()).distinct().toList();
}
private void ensureDailySyncCompletedBeforeDelete(List<FileResultEntity> taskRows) {
if (taskRows == null || taskRows.isEmpty()) {
throw new BusinessException("后台店铺数据尚未完成同步,暂不能删除任务");