Files
crawler-plugin/frontend-vue/tests/rows-version-tracker.test.ts
huangzd1997 5ea52e5291 perf(F5+): 行数据按需拉取(结果行版本信号)+ 修复 progress/light 恒判 missing
行数据按需拉取(审查 F5 后续):
- V125 给 biz_file_result 补 updated_at(DEFAULT/ON UPDATE 由数据库维护,
  实体标注 insertStrategy/updateStrategy=NEVER —— 否则 selectById→updateById 的
  写回会把旧值写回去、ON UPDATE 不触发,版本信号静默冻结)
- 装配器回传 rowsVersion=「最后变更时间毫秒#行数」,5 个品牌工具页版本未变即跳过
  带行明细的重型 batch;前端变更信号为 rowsVersion + status/fileStatus/fileReady 复合
  (任务收尾常见「行早写完、之后才置成功」,只看行版本会把界面卡在旧状态)

修复线上缺陷(同一功能验证时暴露):
- TaskProgressLightAssembler 列裁剪漏选 module_type 却用它做模块过滤 →
  getModuleType() 恒为 null → light 恒把任务判成 missing;第七批把 light 接进
  跟价/定时匹配/商品风险的轮询后,消费方会把运行中任务判为 FAILED
- 补选中列 + 守卫用例 taskQueryMustSelectModuleType(已反向验证:去掉修复即红)
- 前端 lightClaimsAllTasksMissing:整体性 missing 结论用重型端点复核后再采信

契约与文档:light 白名单补 rowsVersion(Java 契约测试 / spec 06 §2 / 12 个端点描述)
测试:mvn test 2901 全绿;前端 npm test 765 全绿
2026-09-14 12:08:25 +08:00

90 lines
3.4 KiB
TypeScript

import { test } from 'node:test'
import assert from 'node:assert/strict'
import { createRowsVersionTracker } from '../src/shared/api/task-progress-polling.ts'
test('首次见到的任务需要拉取行数据', () => {
const tracker = createRowsVersionTracker()
const need = tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '100' }], [1])
assert.deepEqual(need, [1])
})
test('版本未变时不再拉取,版本变化后重新拉取', () => {
const tracker = createRowsVersionTracker()
tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '100' }], [1])
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '100' }], [1]), [], '版本相同跳过')
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '101' }], [1]), [1], '版本变化要拉')
})
test('拿不到版本(老后端/字段缺失)时照旧拉取', () => {
const tracker = createRowsVersionTracker()
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 1 }], [1]), [1])
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: null }], [1]), [1])
assert.deepEqual(tracker.selectTasksNeedingRows([], [7]), [7], '响应里没有该任务也拉')
})
test('多任务各自独立判断', () => {
const tracker = createRowsVersionTracker()
tracker.selectTasksNeedingRows(
[{ taskId: 1, rowsVersion: 'a' }, { taskId: 2, rowsVersion: 'b' }],
[1, 2],
)
const need = tracker.selectTasksNeedingRows(
[{ taskId: 1, rowsVersion: 'a' }, { taskId: 2, rowsVersion: 'b2' }],
[1, 2],
)
assert.deepEqual(need, [2])
})
test('forget 后该任务会被重新拉取(任务重跑场景)', () => {
const tracker = createRowsVersionTracker()
tracker.selectTasksNeedingRows([{ taskId: 5, rowsVersion: 'v1' }], [5])
tracker.forget(5)
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 5, rowsVersion: 'v1' }], [5]), [5])
})
test('任务状态推进(行没变)也要重新拉取', () => {
const tracker = createRowsVersionTracker()
tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '100', status: 'RUNNING' }], [1])
assert.deepEqual(
tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '100', status: 'RUNNING' }], [1]),
[],
'行版本与状态都没变:跳过',
)
assert.deepEqual(
tracker.selectTasksNeedingRows([{ taskId: 1, rowsVersion: '100', status: 'SUCCESS' }], [1]),
[1],
'行版本没变但任务已成功:必须拉取,否则界面卡在运行中',
)
})
test('结果文件状态变化也要重新拉取', () => {
const tracker = createRowsVersionTracker()
tracker.selectTasksNeedingRows([{ taskId: 1, status: 'RUNNING', fileStatus: 'RUNNING', fileReady: false }], [1])
assert.deepEqual(
tracker.selectTasksNeedingRows([{ taskId: 1, status: 'RUNNING', fileStatus: 'RUNNING', fileReady: false }], [1]),
[],
)
assert.deepEqual(
tracker.selectTasksNeedingRows([{ taskId: 1, status: 'RUNNING', fileStatus: 'SUCCESS', fileReady: true }], [1]),
[1],
'文件就绪变化要能触发拉取(下载按钮依赖它)',
)
})
test('四项信号全空视为拿不到信号:每轮都拉取', () => {
const tracker = createRowsVersionTracker()
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 1 }], [1]), [1])
assert.deepEqual(tracker.selectTasksNeedingRows([{ taskId: 1 }], [1]), [1], '老后端不给信号时保持旧行为')
})