fix(采集数据): 品牌检测移出任务锁 + 失败任务仍产出可下载的部分结果

taskId 28599 事故根因:分片回传在任务锁内同步做品牌检测,上游 16890 卡死时
单次持锁 103.5 秒(costMs=103556),期间该任务的心跳与客户端重试全部撞
40902「任务正在处理」,客户端 5 次重试预算耗尽后中止了整个采集。

- submitResult:行归一化 / 去重过滤 / 品牌检测移到任务锁外,锁内只保留落库与终态
- BrandCheckClient:整批加 90 秒总耗时上限(超时按查询失败降级,首轮始终执行),
  单次回传时延从「无上界」收敛到约 90 秒 + 一次读超时
- 失败且已收到分片时照常组装部分结果;任务已 FAILED 则保留失败态与真实失败原因,
  只补结果文件(乐观写结果行 + 条件更新不匹配再补偿写回,避免崩溃时留下「成功但无下载」)
- productrisk / shopmatch 按 pricetrack 的 preserveFailure 样板补齐,含组装落地时
  不再把失败行「洗成成功」
- 前端:采集 / 跟价 / 产品风险 / 店铺匹配的下载按钮放宽到失败任务
This commit is contained in:
2026-09-18 15:53:15 +08:00
parent 986df86e89
commit 9d39705c77
12 changed files with 303 additions and 65 deletions
@@ -1658,7 +1658,8 @@ function statusClass(item: PriceTrackHistoryItem) {
function canDownload(item: PriceTrackHistoryItem) {
if (!item.resultId || (!item.fileReady && !item.downloadUrl)) return false
const st = resolvedTaskStatus(item)
return st === 'SUCCESS' || item.success === true
// 失败任务也可能有已跑出来的部分结果文件(后端按已收分片组装),有文件就允许下载
return st === 'SUCCESS' || item.success === true || st === 'FAILED'
}
async function downloadResult(item: PriceTrackHistoryItem) {