用 meta 校验脚本只跑增量,我先在 1.8 万条上把 40 分钟压到 90 秒

meta 校验脚本一开始是给全量写的:读清单、逐条比对、最后汇总。数据量到 1.8 万条记录时,单次跑完要 40 分钟上下,CI 里基本没人愿意等它,结果就是大家绕开校验直接合。我后来做的不是优化单条速度,而是只跑增量——把「这次变了哪些」交给 git,校验脚本只接变更清单。

环境是 Linux + Python 3.11,meta 目录本身在 git 里,校验脚本会调用一个 validate.py。第一步先拿到变更文件,注意要带 --diff-filter=ACMR,删掉的文件不参与校验:

git diff --name-only --diff-filter=ACMR origin/main...HEAD -- 'meta/**/*.json' > /tmp/changed.txt

第二步让脚本只吃这份清单,没传清单才退回全量,这样本地和 CI 共用一套入口:

python scripts/validate.py --files /tmp/changed.txt --jobs 4

脚本内部对应改成按文件分发,单文件校验逻辑不动,避免改出新的语义差异:

from concurrent.futures import ThreadPoolExecutor

def run(paths):
    with ThreadPoolExecutor(max_workers=4) as pool:
        return list(pool.map(validate_one, paths))

为什么这样做:全量的成本大部分花在重复读没变的文件上,而 git 已经知道哪些文件动过,没必要在校验脚本里再算一遍。代价是校验范围从「全仓库」缩成「本次变更」,一旦有历史遗留的坏数据,增量永远发现不了。所以我保留了一个每周一次的全量任务,增量只负责挡新问题。另外 --jobs 4 是经验值,机器核数少的时候线程切换反而更慢,我试过 8 线程,1.8 万条那个场景下没有收益。

哪里会失效:第一,origin/main 在浅克隆里不存在,CI 要先 fetch --deepen 或者干脆用本地基线分支,否则 diff 直接报错,这个我踩过一次,报错信息很不直观。第二,跨文件引用的问题增量查不出来,比如 A 文件引用了 B 里的字段,这次只改了 B,A 不在清单里就不会被重查。第三,重命名会让旧路径消失、新路径出现,如果校验逻辑依赖路径里的层级信息,要确认 -M 的识别结果符合预期。

现在我更关心的一个问题是:跨文件引用的校验,你们是接受「每周全量兜底」,还是会在增量里顺着引用再展开一层?展开一层的话清单会膨胀多少,我还没实测过。

0
赞同度 100% · 0 条评论 · 6 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。