Linear CI 优化:解决 AI 驱动的开发瓶颈

AI 驱动的编码代理极大地提高了代码交付速度,但验证流水线却未能跟上步伐。在 Linear,这种差异使得持续集成(CI)成为主要瓶颈,增加了基础设施成本,并延迟了开发者和代理的反馈。通过实施多层次的优化策略,Linear 将拉取请求的等待时间从 6 分多钟缩短至 5 分多钟,尽管自今年年初以来其测试套件规模几乎翻了两番。

基础设施和工具升级

升级底层硬件和编译器工具链可以立即带来性能提升,而无需更改 CI 流水线逻辑。

  • 第三方运行器: 将工作负载从 GitHub Actions 迁移到具有更快 CPU、更高性能存储和更优缓存基础设施的第三方运行器,使各作业的平均速度提升了 34%,其中 tsc(TypeScript 编译器)等工作负载提升了 52%。
  • 原生编译: 切换到原生 TypeScript 编译器 tsgo,使 tsc 检查的每周中位数降低了 73%,有效消除了类型检查这一瓶颈。
  • 基于 AST 的代码检查: Linear 重写了自定义代码检查规则,使用基于抽象语法树(AST)的静态分析,而非依赖 TypeScript 类型信息。这使得 ESLint 无需完整类型图即可运行,将 API 代码检查时间减少了 68%,全仓库代码检查时间减少了 55%。
  • Oxlint 集成: 迁移到 Oxlint 进一步减少了用于代码检查的总运行器分钟数,因为它在处理基于语法的规则时效率更高。

优化门禁作业

位于关键路径上的作业——即必须完成才能开始其他任何工作的作业——对 CI 总时长有着不成比例的影响。

高效的变更检测

Linear 优化了根据 PR 差异确定要运行哪些测试的初始作业:

  • 限制获取深度: 通过限制变更检测作业的获取深度,最慢的门禁从 94 秒降至 20 秒。
  • 移除工作树: 对于不需要完整工作树的作业,完全移除了检出步骤,将执行时间从 27 秒降至 7 秒。
  • 稀疏检出: 对于提交推送和合并队列事件,使用具有有限历史的稀疏、无 blob 检出,额外节省了 11 秒。

这些更改将变更检测作业的中位持续时间从 26 秒降至 8 秒。

韧性和路径最小化

为了应对第三方运行器与 GitHub 之间的网络不稳定,Linear 用自定义复合操作替换了 actions/checkout,该操作实现了带退避的重试,并设置了 GIT_HTTP_LOW_SPEED_LIMIT 和 GIT_HTTP_LOW_SPEED_TIME 以防止挂起。此外,他们将非必要任务(如写入缓存标记)移出关键合并路径,为每个 API 拉取请求节省了 42 秒。

减少重复的设置开销

设置成本——启动运行器、安装包和配置依赖项——在短期作业中往往比实际测试消耗更多时间。

  • 自定义 CI 镜像: Linear 将共享依赖项(例如 Postgres 客户端)移入基础 CI 镜像。这消除了每个分片 7-8 秒的 apt 安装时间,并防止了原生构建头文件下载期间偶尔出现的挂起。
  • 过滤依赖安装: 在他们的 pnpm monorepo 中,API 测试工作流被更改为仅安装 API 包及其依赖项,而不是整个工作区。这将 pnpm install 时间从 44-73 秒降至 16-18 秒。
  • 重建与缓存: 测试表明,通过过滤安装重建 node_modules(7.5 秒)比从缓存恢复(28 秒)更快,因此 Linear 放弃了 node_modules 缓存。
  • 模式快照: API 容器现在加载生成的模式快照和引导文件,而不是在每次运行时重放完整的数据库迁移历史,将数据库设置从 12 秒降至 1-2 秒。
  • 作业批处理: 七个独立的短检查被合并为两个并发运行任务的作业。这降低了设置开销的频率,每月节省约 87,000 个运行器分钟(占 CI 总使用量的 11.8%)。

提高测试执行效率

一旦设置成本最小化,Linear 便积极并行化 API 测试套件,这是工作流中最大且最频繁的部分。

平衡工作负载

由于 Vitest 按文件而非测试时长分配工作,几个大文件可能会成为分片的瓶颈。Linear 将这些大文件拆分为更小、更集中的文件,并将分片数量从四个增加到八个。这将最慢分片的持续时间从 5.25 分钟降至 4.33 分钟。

模块状态缓存

通过引入一个选择加入的 Vitest 项目并设置 isolate: false,Linear 允许安全的测试文件在每个工作进程内共享模块注册表。这防止了为每个文件重复构建实体、GraphQL 和装饰器图。这是最大的单一改进,将最慢分片从约 300-379 秒降至 195 秒,并将每次运行的 API 分片总运行器时间从 32.8 分钟削减至 22 分钟。

社区观点和反驳

虽然 Linear 的技术方法侧重于基础设施和流水线效率,但社区讨论突出了更广泛的系统性挑战:

  • AI 测试的价值: 一些贡献者质疑测试套件翻两番是否反映了价值的相应增长,认为 LLM 可能生成大量样板或琐碎的测试。
  • 左移验证: 有人建议将代码检查和单元测试移入代理的本地循环(通过钩子或技能),以便 CI 仅处理资源密集型任务并接收预验证的候选代码。
  • 替代工具: 几位开发者提倡使用 Bazel 或 Grog 等构建系统,这些系统利用激进缓存和依赖图,在大型项目中实现约 10 秒的构建时间。
  • 移动的瓶颈: 工程师们普遍认为,加速 CI 只是将瓶颈进一步向下游移动,转移到人工代码审查、部署和回滚流程。

“加速 CI 只是将瓶颈转移到审查和部署。代理让队列更嘈杂——但它们并没有发明队列。”

SUMMARY: Linear 通过升级基础设施、优化门禁作业、减少设置开销和提高测试执行效率,缩短了拉取请求等待时间,并将每次测试的运行器时间减半,以跟上 AI 加速编码的步伐。

TITLE: Linear CI 优化:解决 AI 驱动的开发瓶颈

Sources

相关