AI 编程把代码写快了,却把 CI 卡住了:Linear 的持续集成改造记录

AI Agent 让代码产出更快,但 Linear 发现验证代码的 CI 成为新瓶颈。通过更换运行环境、优化编译器、减少关键路径开销和降低重复初始化成本,Linear 在测试套件接近四倍增长的情况下,将 PR 等待时间从 6 分钟以上压缩到略高于 5 分钟,并把单次测试的 runner 时间削减约一半。

当 AI Agent 开始大量产出代码,软件研发的第一道瓶颈很快从“写代码”转移到“验证代码”。近期,Linear 工程团队在一篇技术复盘中披露,他们围绕持续集成CI)进行了一轮系统优化:在测试套件几乎增长到年初四倍的情况下,将 Pull Request 的平均等待时间从 6 分钟以上压缩到略高于 5 分钟,同时把单次测试占用的 runner 时间大约削减一半。

这件事的起点很朴素。Linear 的 CTO Tuomas 给工程师分配了一个标题为“CI 成本很高”的任务,要求同时解决成本和速度问题。随着 Agent 让代码提交速度指数级提升,每个 PR 仍要经过完整 CI 验证,测试资源、基础设施消耗和开发者等待时间随之上升。CI 不再是后台流程,而是新的交付瓶颈。

更快的机器、更快的编译器:基础设施先换一遍

Linear 的代码库主要基于 TypeScript,但他们的不少优化思路对其他语言同样适用。最先见效的措施并不是重写流水线,而是更换运行环境:把原本跑在 GitHub Actions 上的工作负载迁移到第三方 runner。这些机器拥有更快的 CPU、更高性能的存储和更好的缓存基础设施。切换前后两天的对照数据显示,任务平均运行速度提升 34%,其中 tsc 类型检查这类负载耗时下降了 52%。

工具链升级带来了更明显的收益。Linear 将 TypeScript 编译器切换到 tsgo,这是一个原生 TypeScript 编译器。切换后,tsc 检查的每周中位数耗时下降了 73%,类型检查不再是整个 CI 的主要瓶颈。

  • 迁移到第三方 runner 后,任务平均速度提升 34%
  • tsc 类负载耗时下降 52%
  • 切换到 tsgo 后,tsc 检查每周中位数耗时下降 73%

Lint 和前置检查:把关键路径上的“小任务”削薄

基础设施提速之后,Linear 开始处理流水线中反复消耗时间的具体环节。Lint 是早期重点目标之一。此前,部分自定义 lint 规则依赖 TypeScript 类型信息,每次运行都要先构建完整类型图,导致 lint 成为内存消耗最高的 CI 任务之一。

团队重写了这些规则,改为直接基于抽象语法树做静态分析,不再依赖类型信息。调整后,ESLint 可以完全脱离 TypeScript 运行,API lint 时间下降 68%,全仓库 lint 时间下降 55%,内存占用也明显降低。由于规则只依赖语法结构,后续迁移到 Oxlint 也更顺畅,进一步减少了 lint 消耗的 runner 分钟数。

更隐蔽的瓶颈出现在所有任务之前的“门控检查”。Linear 的每次 CI 运行都会先判断 PR 修改了哪些路径,以及相同输入下的测试是否已经通过。为了避免无意义任务占用 runner,这些检查被放在任务级别,但这也让它们处于关键路径:8 个 API 测试分片都必须等这些前置任务完成才能启动。

  • API lint 时间下降 68%
  • 全仓库 lint 时间下降 55%
  • 变更检测门控任务从 94 秒降到 20 秒
  • 无需工作树的任务移除 checkout 后,从 27 秒降到 7 秒
  • commit push 和 merge-queue 场景改用稀疏、无 blob、有限历史的 checkout,约节省 11 秒

网络稳定性也曾拖累 checkout。迁移到第三方 runner 后,由于机器位于 GitHub 网络之外,部分 checkout 时间变长甚至偶发挂起。Linear 用自研复合动作替代官方 actions/checkout,加入退避重试,并设置 GIT_HTTP_LOW_SPEED_LIMIT 与 GIT_HTTP_LOW_SPEED_TIME,让卡住的连接大约 30 秒后中止,而不是无限等待。同时,checkout 缓存会在粘性磁盘上维护一个持久 git 镜像,减少了关键任务因等待代码拉取而空转的情况。

合并队列与重复成本:测试通过后别再排队

Linear 还发现,并非所有关键路径任务都必须存在。过去,团队在合并前最后一个检查中写入缓存标记,这意味着即使测试已经通过,PR 仍可能停留在合并队列中。后来,这个写操作被移到一个不阻塞合并的任务里,仅在测试分片完成后执行。对每个 API PR 和合并队列条目来说,这一步为合并路径节省了 42 秒。

另一类重复消耗来自每个任务的启动成本:拉起 runner、安装依赖、准备构建环境。一个实际只工作几秒钟的任务,可能因此消耗数分钟基础设施时间。Linear 的一个例子是,每个 API 测试分片都要用 apt 安装同一个 Postgres 客户端,每次耗时 7 到 8 秒。团队把它预装进一个包含 Node 和该客户端的 CI 基础镜像,让分片从“就绪环境”直接开始。后来,他们又把所需的原生构建头文件加入镜像,因为运行中临时下载这些依赖偶尔会挂起,进一步缩短了长尾耗时。

这些改动叠加后,使 API PR 在缓存未命中时的必要检查大约减少了 1 分钟,同时降低了 runner 启动次数。素材中关于 Linear monorepo 和 pnpm workspace 的后续内容尚未完整披露,因此本文只覆盖已确认部分。

对普通团队的启示:AI 时代先重排验证流程

Linear 这次改造没有依赖单一“银弹”,而是沿着四个方向推进:更强的运行环境、更快的工具链、更少的关键路径开销、更低的重复启动成本。对于正在引入 AI 编程工具的团队,这份记录提供了几个可直接参考的方向。

  • 当 PR 数量上升时,先关注等待时间和资源消耗,而不是只盯着测试是否通过。
  • 把变更检测、路径过滤、缓存命中等前置任务视为关键路径,避免小任务阻塞大任务。
  • 尽量减少每个任务的重复初始化,例如预装依赖、使用基础镜像、复用构建缓存。
  • 测试通过后的非阻塞动作不要放在合并队列中,减少“已通过但仍在排队”的浪费。
  • 网络不稳定时,需要为 checkout 和依赖下载设置超时、重试与本地缓存。

AI 生成代码的速度仍在提升,但代码能否安全合入,取决于验证系统能否跟上。Linear 的实践说明,CI 不再只是工程配套,而正在成为 AI 编程时代的核心基础设施。谁先把它从“拖慢流程的检查器”改造成“快速反馈的验证系统”,谁就能更早释放 AI 编程带来的效率。

原创文章,作者:点点,如若转载,请注明出处:https://www.dian8dian.com/ai-bian-cheng-ba-dai-ma-xie-kuai-liao-que-ba-ci-ka-zhu-le

Like (0)
点点的头像点点
Previous 2小时前
Next 30 mins ago

相关推荐