← 中文资源

简体中文版本

GitHub Actions 缓存未命中 — 为什么缓存从未恢复

排查 GitHub Actions 缓存 key 不稳定、分支作用域、路径不匹配与配额淘汰,设计真正能命中的 key 与 restore-keys。

阅读英文原文

现象

日志出现 Cache not found for input keys;每次运行都重新安装依赖;保存成功但下次仍 miss;主分支能命中而 PR 不能。

诊断

先看 workflow 里的 key 表达式,再列出仓库缓存:

grep -n -B3 -A8 'actions/cache' .github/workflows/ci.yml
gh cache list --limit 30
gh run view $(gh run list --limit 1 --json databaseId --jq '.[0].databaseId') --log | grep -iE 'cache (restored|saved|not found)|reserve cache'

key 里出现 github.run_id、github.sha 或时间戳,永远不可能命中。hashFiles('pnpm-lock.yaml') 相对于 workspace 计算,monorepo 必须写实际路径,否则哈希的是空集合。日志会打印解析后的 key 与恢复结果:not found 且 Failed to reserve cache 多为配额或作用域问题,而不是语法错误。

根因

恢复的 key 在作业可见的作用域内不存在。缓存不可变,并按分支、PR merge ref 与缓存版本隔离;key 不稳定、路径错误、缓存写在其他分支或超出 10 GB 被 LRU 淘汰,都会导致 miss。

修复

使用固定前缀加 lockfile 哈希,并加 restore-keys 兜底;缓存包管理器 store 而不是 node_modules:

- uses: actions/cache@v4
  with:
    path: ~/.local/share/pnpm/store
    key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
    restore-keys: |
      ${{ runner.os }}-pnpm-

不要在 key 中放 run_id 或 sha;需要主动失效时改版本后缀。PR 的缓存按 merge ref 隔离,不要把 PR 自己写入的缓存当作下一次运行的前提,也不要缓存密钥或 .env 文件。

验证

同一分支连续运行两次且不改 lockfile,第二次日志应出现 Cache restored from key 且安装步骤明显变短;修改 lockfile 后应先 miss、保存,再下一次命中。gh cache list 中能看到对应条目。