task-58: collectdata 结果明细读取失败降级(RustFS 超时跳过该 chunk,不中断其它 chunk)

chunk 级引用读取失败(RustFS 超时/不可用)时降级为跳过该 chunk 的引用行并记录 warn,
结果文件继续生成,缺失行由任务状态可观测;chunk 明细 JSON 损坏仍抛异常(数据问题不降级),
旧格式单行读取失败保持抛异常。失败 chunk 在单次调用内缓存为空哨兵,避免重复 resolve。
task-052 依赖失败测试同步更新为降级语义。
This commit is contained in:
2026-08-30 17:31:21 +08:00
parent 44abcdd4ef
commit 567cb1ab67
3 changed files with 234 additions and 7 deletions
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.nanri.aiimage.modules.collectdata.model.vo.CollectDataResultRowVo;
import com.nanri.aiimage.modules.task.model.entity.TaskResultItemEntity;
import com.nanri.aiimage.modules.task.service.TransientPayloadStorageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@@ -19,6 +20,7 @@ import java.util.Map;
* 空列表,越界/损坏行安全跳过,读取失败抛可识别异常。
*/
@Component
@Slf4j
public class CollectDataResultDetailReader {
private static final String ERROR_DETAIL = "read collect data result detail failed";
@@ -54,10 +56,24 @@ public class CollectDataResultDetailReader {
if (ref != null) {
List<CollectDataResultRowVo> details = detailCache.get(ref.pointer());
if (details == null) {
String detailJson = transientPayloadStorageService.resolvePayload(ref.pointer(), ERROR_DETAIL);
details = (detailJson == null || detailJson.isBlank())
? null
: objectMapper.readValue(detailJson, listType);
try {
String detailJson = transientPayloadStorageService.resolvePayload(ref.pointer(), ERROR_DETAIL);
// 空内容用空列表占位:与缓存 miss 区分,避免同一 chunk 重复 resolve。
details = (detailJson == null || detailJson.isBlank())
? List.of()
: objectMapper.readValue(detailJson, listType);
} catch (Exception readEx) {
// RustFS 超时/不可用等读取失败:跳过该 chunk 的引用行,
// 不中断其它 chunk 的行读取(结果文件降级生成,缺失行
// 由任务状态可观测);chunk 明细 JSON 损坏则正常上报,
// 属于数据问题而非依赖降级。
if (readEx instanceof com.fasterxml.jackson.core.JsonProcessingException) {
throw readEx;
}
log.warn("[collect-data] skip chunk detail read failed pointer={} err={}",
ref.pointer(), readEx.getMessage());
details = List.of();
}
detailCache.put(ref.pointer(), details);
}
if (details != null && ref.offset() >= 0 && ref.offset() < details.size()) {