多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Comp AI CRM 中的 Turborepo 缓存机制:哈希方程、全局输入与缓存失效实践

Comp AI CRM 中的 Turborepo 缓存机制:哈希方程、全局输入与缓存失效实践 后端前端CRM人工智能AI Agent【免费下载链接】crmComp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.项目地址https://gitcode.com/gh_mirrors/crm48/crm点击查看免费下载本文以 Comp AI CRMAgentic-first CRM开源仓库gh_mirrors/crm48/crm为背景深入解析 Turborepo 的缓存工作原理缓存键由哪些输入决定、globalDependencies与global.inputs的哈希差异、缓存被恢复与失效的完整流程并结合仓库根目录与各包的turbo.json真实配置给出缓存调试--summarize、--dry、--force与远程缓存落地的一线实战方案。读完你既能看懂FULL TURBO背后的数学原理也能在自己的 monorepo 中精准控制缓存命中率。从一句核心原则说起Turborepo 的核心原则只有一句话永远不要重复做同样的工作never do the same work twice。这套机制的全部细节——哈希、输入、输出、恢复——都是为了把这句话变成现实。Comp AI CRM 仓库本身就是这一原则的最佳实践样本仓库采用apps/*与packages/*的 workspace 结构见 package.json包含apps/agent、apps/api、apps/app三个应用和packages/auth、packages/db、packages/ui、packages/validation、packages/telemetry等共享包根 package.json 的脚本全部委派给 Turbo如build: turbo run build、test: turbo run test --concurrency1真正的任务编排与缓存策略都定义在 turbo.json 和各包的turbo.json中。缓存方程输入决定输出Turborepo 的缓存机制可以压缩成一条方程fingerprint(inputs) → stored outputs当某个任务的输入没有变化时Turborepo 直接从缓存恢复输出而不会重新执行任务。这里的inputs并不是简单的文件列表而是一整套被纳入哈希计算的指纹要素。理解缓存本质上就是理解这条方程左右两边各装了什么。缓存键由什么决定全局哈希输入Global Hash Inputs以下输入会影响仓库中所有任务的缓存键任何一项变化都会导致全仓失效package-lock.json/yarn.lock/pnpm-lock.yaml等锁文件Comp AI CRM 使用 Bun对应bun.lockglobalDependencies或启用globalConfiguration后的global.env中列出的文件globalEnv或global.env中列出的环境变量turbo.json配置文件本身典型配置示例{ globalDependencies: [.env, tsconfig.base.json], globalEnv: [CI, NODE_ENV] }在 Comp AI CRM 的根 turbo.json 中可以观察到对应实现globalEnv声明了NODE_ENVglobalPassThroughEnv则放行了DATABASE_URL、BETTER_AUTH_SECRET、GOOGLE_CLIENT_ID、SLACK_CLIENT_ID、PERPLEXITY_API_KEY、AI_GATEWAY_API_KEY、AGENT_BRIDGE_SECRET、CRM_TELEMETRY_DISABLED、VERCEL等几十个变量。注意这里区分了两种角色globalEnv这些变量的值参与全局哈希计算值一变全仓缓存失效globalPassThroughEnv只负责把变量透传给任务运行时使用不参与哈希因此不会引起缓存失效详见下文严格模式过滤。任务哈希输入Task Hash Inputs以下输入仅影响具体某个任务的缓存键包目录下的所有文件除非被inputs过滤package.json的内容任务env键中声明的环境变量任务配置本身command、outputs、dependencies依赖任务的哈希dependsOn声明的上游任务启用futureFlags.globalConfiguration后来自global.inputs的文件配置示例{ tasks: { build: { dependsOn: [^build], inputs: [src/**, package.json, tsconfig.json], env: [API_URL] } } }在 Comp AI CRM 中同样能找到真实对应根 turbo.json 的build任务声明了dependsOn: [^build]、env: [API_URL, APP_URL, NEXT_PUBLIC_API_URL]、inputs: [$TURBO_DEFAULT$, .env*]以及排除了.next/cache/**和.next/dev/**的outputs而 apps/app/turbo.json 作为包级配置进一步收窄到.next/**、!.next/cache/**、!.next/dev/**并为 Next.js 构建声明了NEXT_PUBLIC_API_URL、NEXT_PUBLIC_AUTH_URL两个环境输入。global.inputs如何改变哈希方程当启用futureFlags.globalConfiguration后global.inputs中的文件不再进入全局哈希而是被前置拼接到每个任务的 inputs 中并折叠进任务哈希。这与globalDependencies有本质区别。使用globalDependencies默认行为task cache key hash(global hash, task hash) ↑ 包含 globalDependencies 文件哈希只要某个globalDependencies文件变化每个任务都会失效——无论任务的inputs怎么配任务都无法退出这种失效没有例外。使用global.inputsfutureFlags.globalConfigurationtask cache key hash(global hash, task hash) ↑ 包含 global.inputs 文件哈希与任务 inputs 合并global.inputs的文件被合并进每个任务的输入 glob这意味着任务可以用否定 glob排除特定全局文件inputs: [$TURBO_DEFAULT$, !$TURBO_ROOT$/tsconfig.json]全局哈希更小仍包含锁文件、engines、global.env等但不再包含global.inputs文件的内容哈希任务哈希正确地把全局输入文件哈希与任务自身输入合并在一起完整示例{ futureFlags: { globalConfiguration: true }, global: { inputs: [tsconfig.json, .env] }, tasks: { build: { outputs: [dist/**] }, lint: { inputs: [$TURBO_DEFAULT$, !$TURBO_ROOT$/tsconfig.json] } } }在这个例子中修改tsconfig.json会使build失效它出现在任务的 inputs 中但不会使lint失效它被显式排除。如果使用globalDependencies两者都会被失效。这正是global.inputs带来的细粒度缓存控制能力。什么会被缓存Turborepo 为每个任务缓存两类东西文件输出File outputsoutputs中指定的文件/目录任务日志Task logsstdout/stderr用于缓存命中时回放{ tasks: { build: { outputs: [dist/**, .next/**] } } }Comp AI CRM 的配置对这两点体现得淋漓尽致根 turbo.json 的build任务输出.next/**、dist/**、.output/**并显式用否定 glob 排除!.next/cache/**、!.next/dev/**——Next.js 自身的构建缓存和 dev 产物被排除在 Turborepo 缓存之外避免重复打包无用文件apps/api/turbo.json 为 API 声明了dist/**输出其trpc:generate任务则以src/**/*.ts为输入、src/generated/**为输出实现 tRPC 代码生成的增量缓存。本地缓存位置默认情况下缓存产物存放在仓库根目录的.turbo/cache/下.turbo/cache/ ├── hash1.tar.zst # 压缩后的输出 ├── hash2.tar.zst └── ...每个文件都以哈希命名内容经过.tar.zstzstd 压缩的 tar 归档打包。Comp AI CRM 已在根 .gitignore 中加入.turbo确保缓存不会污染版本库。缓存恢复流程缓存命中时Turborepo 依次执行将归档的输出解压回其原始位置回放之前记录的 stdout/stderr 日志将该任务标记为 cached终端显示FULL TURBO一个完整的示例流程# 第一次运行 - 执行构建并缓存结果 turbo build # → packages/ui: cache miss, executing... # → packages/web: cache miss, executing... # 第二次运行 - 输入未变从缓存恢复 turbo build # → packages/ui: cache hit, replaying output # → packages/web: cache hit, replaying output # → FULL TURBO在 Comp AI CRM 中运行bun run build即turbo run build即可观察到这一现象apps/agent、apps/api、apps/app以及packages/*的构建任务会先按dependsOn拓扑排序首次执行后全部缓存后续重复执行直接回放日志并输出FULL TURBO。关键要点速览缓存是内容寻址的基于输入哈希而非时间戳空的outputs数组意味着任务照常运行但什么都不缓存没有outputs键的任务不缓存任何东西想显式表达不缓存请用outputs: []任何输入变化都会使缓存失效实战调试缓存问题来自配套技能文档缓存机制再优雅落地时也难免遇到该命中却 miss或该失效却 hit的情况。仓库内的技能文档 .agents/skills/turborepo/references/caching/gotchas.md 给出了完整的调试工具箱。诊断工具# 生成包含全部哈希输入的 JSON 文件对比两次运行找差异 turbo build --summarize # → 创建 .turbo/runs/run-id.json # 对比两次运行 diff .turbo/runs/first-run.json .turbo/runs/second-run.json # 不实际执行预览哪些任务会运行及缓存状态 turbo build --dry turbo build --dryjson # 机器可读输出 # 跳过缓存读取强制重跑所有任务验证任务本身真的能工作 turbo build --force--summarize生成的摘要包含全局哈希及其输入、每个任务哈希及其输入、影响哈希的环境变量。--dry则在不执行任何任务的情况下展示每个任务的缓存状态。意外缓存失效Expected Hit实际 Miss症状任务在预期命中时却重新执行。环境变量变化检查env键中的变量是否变了。API_URL两次运行不同 缓存失效。.env文件变化.env默认不参与哈希。需要显式加入inputs{ tasks: { build: { inputs: [$TURBO_DEFAULT$, .env, .env.local] } } }或全仓共享用globalDependencies: [.env]启用globalConfiguration后用global.inputs区别在于后者折叠进任务哈希任务可用否定 glob 排除。锁文件变化安装/升级依赖会改变全局哈希。源码文件变化包内任意文件或在inputs中变化触发失效。turbo.json 变化配置改动使全局哈希失效。Comp AI CRM 的根 turbo.json 在build的inputs中写了.env*正是为了让各应用能感知.env文件变化而主动失效重建。错误的缓存命中Expected Miss实际 Hit症状缓存输出是过期的、错误的。环境变量缺失任务使用了未在env中声明的变量。例如build.js里process.env.API_URL不在env数组中则该变量变化不会触发重建。修复加入任务配置的env。输入文件缺失任务读取了默认 inputs 之外的文件需要显式声明包括包外的文件{ tasks: { build: { inputs: [ $TURBO_DEFAULT$, ../../shared-config.json ] } } }实用标志# 只显示缓存 miss 任务的输出 turbo build --output-logsnew-only # 显示所有输出调试用 turbo build --output-logsfull # 查看任务为什么运行 turbo build --verbosity2快速检查清单缓存失效该命中却 miss时用--summarize运行并与上一次对比用--dryjson检查环境变量在 git 中查看锁文件/配置变更缓存误命中该失效却 hit时确认环境变量在env数组中确认文件在inputs数组中检查文件是否位于包目录之外启用globalConfiguration后的调试要点当futureFlags.globalConfiguration开启时global.inputs的文件出现在任务哈希输入而非全局哈希中。若出现意外 miss查看--summarize输出——全局输入文件应出现在任务 inputs 区而非全局哈希区确认任务没有用否定 glob 意外排除全局输入记住切换globalConfiguration标志本身会使全部缓存失效标志值是全局哈希的一部分若出现意外 hit很可能是任务用!$TURBO_ROOT$/...模式排除了该全局文件。远程缓存让团队和 CI 共享命中本地缓存只对单机有效。Turborepo 的远程缓存详见 .agents/skills/turborepo/references/caching/remote-cache.md把缓存产物上传到远端实现团队协作与 CI 加速团队成员之间互相命中缓存CI 从本地开发结果命中缓存反之亦然首次构建后 CI 大幅提速告别我机器上明明是好的Vercel Remote Cache在 Vercel 上部署时免费且零配置本地开发和其他 CI 需要两步# 向 Vercel 认证 npx turbo login # 将仓库关联到你的 Vercel team npx turbo link这会生成.turbo/config.json默认已被 gitignore其中包含团队信息。CI 环境则通过环境变量配置TURBO_TOKENyour-token TURBO_TEAMyour-team-slugGitHub Actions 示例- name: Build run: npx turbo build env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ vars.TURBO_TEAM }}turbo.json 中的远程缓存配置{ remoteCache: { enabled: true, signature: false } }enabled开关远程缓存默认认证后开启signature要求产物签名默认false产物签名防止缓存产物被篡改在所有环境使用同一把密钥然后在配置中开启签名export TURBO_REMOTE_CACHE_SIGNATURE_KEYyour-secret-key{ remoteCache: { signature: true } }签名产物只有在签名匹配时才能恢复。自托管远程缓存社区实现包括turbo-remote-cacheNode.js——支持 S3、GCS、Azureturborepo-remote-cacheGo——轻量兼容 S3ducktapeRust——高性能方案通过环境变量接入TURBO_APIhttps://your-cache-server.com TURBO_TOKENyour-auth-token TURBO_TEAMyour-team缓存行为控制# 本次运行只读远程缓存不写入 turbo build --remote-cache-read-only # 完全跳过缓存 turbo build --no-cache # 环境变量替代只用远程缓存跳过本地 TURBO_REMOTE_ONLYtrue远程缓存调试# 详细输出展示缓存操作 turbo build --verbosity2 # 检查远程缓存是否已配置 turbo config关注输出中的Remote caching enabled、运行期间的 upload/download 消息、cache hit, replaying output 是否带有远程缓存标识。仓库内更多配套资料想要进一步深入Comp AI CRM 的.agents/skills/turborepo技能包还提供了完整的分支资料配置总览turbo.json 概览、Package Configurations任务配置dependsOn、outputs、inputs、env、cache、persistent全局选项globalEnv、globalDependencies、global、futureFlags、cacheDir、envMode环境变量规则env、globalEnv、passThroughEnv过滤与影响分析--filter、--affectedCI 最佳实践GitHub Actions、Vercel 部署、turbo-ignore其中--affected是只跑变更包的首选方式——自动对比默认分支并纳入受影响的下游包。Comp AI CRM 根 turbo.json 中build/lint/check-types/test/dev的任务编排^build依赖传递、cache: false与persistent: true的 dev 任务也值得对照阅读它演示了任务级env、inputs、outputs与$TURBO_EXTENDS$包级继承见 apps/api/turbo.json的组合用法。结语Turborepo 的缓存本质是一条简单方程输入指纹决定输出是否复用。掌握全局哈希与任务哈希的分工、globalDependencies与global.inputs的取舍、outputs/env/inputs三键的正确声明再配合--summarize、--dry、--force三大调试工具你就能像 Comp AI CRM 这样在拥有 Agent、API、Web 应用与多个共享包的大型 monorepo 中稳定拿到FULL TURBO。赞分享后端前端CRM人工智能AI Agent【免费下载链接】crmComp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.项目地址https://gitcode.com/gh_mirrors/crm48/crm点击查看免费下载相关推荐深入解析 Langfuse 仓库中的 Turborepo 缓存机制哈希方程、缓存键与失效策略实战深入解析 Langfuse 仓库中的 Turborepo 缓存机制哈希方程、缓存键与失效策略实战 导读 本文以 Langfuse 开源仓库AI 可观测性与人工智能LLMOps可观测性AI 评测LLM 网关后端前端Turborepo 缓存机制全解析从缓存方程到 global.inputs 的哈希深入指南Turborepo 缓存机制全解析从缓存方程到 global.inputs 的哈希深入指南 Turborepo 是一个用 Rust 编写的 JavaScrip构建工具开发工具CLIVSCode办公插件终极指南告别应用切换拥抱一站式开发办公体验VSCode办公插件终极指南告别应用切换拥抱一站式开发办公体验 你是否曾为频繁切换应用而烦恼一边在VSCode中编写代码一边需要查看PDF文档、Exce后端前端CRM人工智能AI Agent上一篇Rerun 0.28 → 0.29 迁移指南Python API、CLI 与数据集注册的破坏性变更全解析下一篇5分钟终极指南如何轻松使用BOTW存档编辑器修改《塞尔达传说旷野之息》创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表