Skip to content

fix: pre-render all non-frozen QMDs to fix babelquarto freeze cache miss#278

Merged
ShixiangWang merged 1 commit into
mainfrom
copilot/optimize-build-cache-usage
Apr 16, 2026
Merged

fix: pre-render all non-frozen QMDs to fix babelquarto freeze cache miss#278
ShixiangWang merged 1 commit into
mainfrom
copilot/optimize-build-cache-usage

Conversation

Copilot AI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

问题分析 / Root Cause

通过详细分析 CI 日志(run 24491897842),发现 freeze cache 从未被正确保存。

babelquarto::render_website() 内部机制如下(源码):

render <- function(path = ".", ...) {
    temporary_directory <- withr::local_tempdir()  # 创建临时目录
    fs::dir_copy(path, temporary_directory)         # 复制整个项目到临时目录
    withr::with_dir(file.path(temporary_directory, ...), {
        quarto::quarto_render(...)  # 在临时目录中渲染,_freeze 创建在此
    })
    fs::dir_copy(
        file.path(temporary_directory, ..., output_dir),  # 只把 _site 复制回来
        path
    )
    # render() 返回时,withr 自动删除临时目录(包含 _freeze)
}

根本原因:babelquarto 在临时目录中渲染,将新的 _freeze 条目写入临时目录,然后只把 _site 复制回工作区,最后临时目录被删除。工作区的 _freeze 从未更新,导致 Save freeze cache 步骤只能找到约 6 个 Julia 预渲染条目,而不是 500+ 个。

证据

  • "Save freeze cache" 步骤耗时 0.4 秒(保存 6 个条目),而非几十秒(保存 500+ 个条目)
  • 下一次 run 的 "Restore freeze cache" 耗时 1 秒(只有 6 个条目)
  • babelquarto 渲染仍然处理 528 个文件并执行所有 R 代码(每次都是)

修复方案 / Fix

在 babelquarto 运行之前,添加"Pre-render all non-frozen QMD files"步骤,直接将 freeze 条目写入工作区的 _freeze 目录:

  1. 工作区 _freeze 被完全填充(500+ 条目)
  2. babelquarto 通过 fs::dir_copy() 将完整的 _freeze 复制到临时目录
  3. babelquarto 内部 filter_freeze_directory().zh freeze 条目重命名以匹配重命名后的 .qmd 文件
  4. babelquarto 调用 quarto::quarto_render() 时,所有文件都有 freeze 条目 → 跳过代码执行,只运行 pandoc
  5. Save freeze cache 步骤在工作区找到完整的 _freeze 并保存

预期效果 / Expected Performance

Run type Before fix After fix
Cold cache (first run) ~90 min ~95–115 min (slightly slower due to pre-render step then fast babelquarto)
Warm cache (subsequent) ~90 min (full re-render every time!) ~35 min (~3× faster)

其他变更 / Other Changes

  • 超时时间从 120 分钟增加到 180 分钟,为冷缓存首次运行提供安全余量
  • 更新注释,准确说明 freeze cache 的工作机制

babelquarto renders in a temp dir (withr::local_tempdir()), creates _freeze
there, copies only _site back to workspace, then deletes the temp dir.
The workspace _freeze was never updated, so Save freeze cache only found
~6 entries (just the changed-file pre-renders) instead of 500+.

Fix: add "Pre-render all non-frozen QMD files" step before babelquarto.
This writes freeze entries to the workspace _freeze. babelquarto then
copies the full _freeze into its temp dir via fs::dir_copy() and uses
filter_freeze_directory() to match freeze entries to renamed .zh.qmd files,
skipping all code execution (pandoc-only ~20 min vs ~90 min full re-render).

Also increase timeout from 120 to 180 minutes for cold-cache first runs.

Agent-Logs-Url: https://github.com/openbiox/Bizard/sessions/164ab16f-4599-4163-b722-0777d1ae60dd

Co-authored-by: ShixiangWang <25057508+ShixiangWang@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ QMD Format Check

No new QMD tutorial files to check.

Automated check by the PR Review workflow.
See contribution guidance for the expected tutorial format.

@ShixiangWang

Copy link
Copy Markdown
Member

@copilot 是否进行了整个流程的模拟测试和可靠性验证?

Copilot AI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot 是否进行了整个流程的模拟测试和可靠性验证?

没有在真实 CI 上全流程运行(需要约 95-115 分钟),但进行了以下可靠性验证:

1. 根本原因已通过 CI 日志证实

  • 上一次成功运行(run 24491897842)中,"Save freeze cache" 步骤耗时 0.4 秒(仅保存 6 个 Julia 条目)
  • 下一次运行恢复缓存也只有 6 个条目,babelquarto 仍然重新执行了 528 个文件(~83 分钟)
  • 通过阅读 babelquarto 源码确认:render_website()withr::local_tempdir() 中渲染,只把 _site 复制回工作区,_freeze 从不写回

2. 核心逻辑(freeze 路径计算)本地验证通过

冷缓存模拟(无 _freeze):520 个文件需要渲染,6 个 Julia 跳过 ✓
热缓存模拟(_freeze 已填充):0 个文件需要渲染,全部跳过 ✓

Distribution/ViolinPlot.qmd    → _freeze/Distribution/ViolinPlot/
Distribution/ViolinPlot.zh.qmd → _freeze/Distribution/ViolinPlot.zh/

3. babelquarto 的 filter_freeze_directory 兼容性验证

  • 英文渲染:直接使用 _freeze/Distribution/ViolinPlot/
  • 中文渲染:filter_freeze_directory_freeze/Distribution/ViolinPlot.zh/ 重命名为 _freeze/Distribution/ViolinPlot/,匹配重命名后的 .qmd

4. 已知限制

唯一无法本地验证的是:Quarto 在 babelquarto 的临时目录中,用存储的哈希校验冻结条目时是否正确匹配(文件路径变了但内容相同)。如果出现哈希不匹配,最坏结果是首次运行仍然重新执行代码,但不会报错——后续运行会得到正确的缓存。可在下次 CI 运行时通过观察 "Pre-render all non-frozen QMD files" 步骤的渲染数量和 "Save freeze cache" 的耗时来确认。

@ShixiangWang ShixiangWang marked this pull request as ready for review April 16, 2026 09:40
@ShixiangWang ShixiangWang merged commit 7aa5a09 into main Apr 16, 2026
3 of 4 checks passed
@ShixiangWang ShixiangWang deleted the copilot/optimize-build-cache-usage branch April 16, 2026 09:40
Copilot stopped work on behalf of ShixiangWang due to an error April 16, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants