意外と情報がない(Remote Cachingを除く)のでメモ。
Linux上ではキャッシュを有効にしているものの、Windows上では1時間以上かけてビルドしているプロジェクトがままある(ただし、キャッシュを有効にすれば速くなるとも言えないので、意図的かもしれない)。
Linuxでの例
setup-bazeliskのページに書かれている通りで、キャッシュディレクトリをそのまま @actions/cache
でキャッシュすれば良い。
https://github.com/bazelbuild/setup-bazelisk#usage
jobs:
build:
runs-on: ubuntu-latest
steps:
...
- name: Mount bazel cache
uses: actions/cache@v3
with:
path: "~/.cache/bazel"
key: bazel-v1-cache
Windowsでの問題の所在
ところが、Windowsだと上記の方法でうまく行かない。
jobs:
build:
runs-on: windows-latest
steps:
# ...
- name: Mount bazel cache
uses: actions/cache@v3
with:
path: C:\_bzl
key: bazel-v1-cache
- run: |
bazel --output_user_root=C:\_bzl build ..
output_user_root
が C:\_bzl
だとして、path
に C:\_bzl
を指定すると、以下のようにキャッシュ作成処理(Post Mount bazel cache
)に失敗する。
Post job cleanup.
C:\Windows\System32\tar.exe --posix -z -cf cache.tgz --exclude cache.tgz -P -C D:/a/repository/repository --files-from manifest.txt
tar.exe: Couldn't open C:/_bzl/l2nyujfy/java.log.fv-az455-530.runneradmin.log.java.20220701-105515.2912: Permission denied
tar.exe: Error exit delayed from previous errors.
Warning: Tar failed with error: The process 'C:\Windows\System32\tar.exe' failed with exit code 1
Job自体はエラーにならないものの、キャッシュがアップロードされていないので、次の実行時にもキャッシュが見つかることはない。
Cache not found for input keys: bazel-v1-cache
これを解決する方法として、MSYS2でインストールされているGNUのtarを使う方法がある。
jobs:
build:
runs-on: windows-latest
steps:
# ...
# Restoreする前に実行しないと、Keyがヒットしているにもかかわらず、Cache not foundになるので注意
- run: echo "C:\msys64\usr\bin" >> $env:GITHUB_PATH
- name: Mount bazel cache
uses: actions/cache@v3
with:
path: C:\_bzl
key: bazel-v1-cache
- run: |
bazel --output_user_root=C:\_bzl build ..
GNUのtarを使うと、キャッシュの作成・アップロードに成功するようになる。
Post job cleanup.
C:\msys64\usr\bin\tar.exe --posix --use-compress-program "zstd -T0" -cf cache.tzst --exclude cache.tzst -P -C D:/a/repository/repository --files-from manifest.txt --force-local
Cache Size: ~1833 MB (1922026652 B)
Cache saved successfully
Cache saved with key: bazel-v1-cache
しかし、次の実行時、キャッシュのリストアに失敗してしまう(Jobの実行自体はエラーにならない。後ほど、bazel build
が失敗する可能性はあるが……)。
/usr/bin/tar: C\:/_bzl/l2nyujfy/external/androidsdk/ndk-bundle: Cannot create symlink to '/c/Android/android-sdk/ndk-bundle': Permission denied
/usr/bin/tar: C\:/_bzl/l2nyujfy/external/llvm-raw/libcxx/test/std/pstl: Cannot create symlink to '/c/_bzl/l2nyujfy/external/llvm-raw/pstl/test/std': No such file or directory
/usr/bin/tar: C:/_bzl/l2nyujfy/external/local_config_cc/windows_cc_toolchain_config.bzl: time stamp 2032-06-29 04:38:53.9788293 is 315262677.9849176 s in the future
/usr/bin/tar: Exiting with failure status due to previous errors
Warning: Tar failed with error: The process 'C:\msys64\usr\bin\tar.exe' failed with exit code 2
解決策
本質的には、read権限があるはずのファイルでなぜか発生する Permission denied
(tar.exe: Couldn't open C:/_bzl/l2nyujfy/java.log.fv-az455-530.runneradmin.log.java.20220701-105515.2912: Permission denied
) と、symlinkに関する問題の2つを解決する必要がある。
実は、前者の問題は、 bazel shutdown
するだけで解決する(Bazelがlogファイルを開いているのが原因と思われる)。
後者のsymlinkは bazel
が実行時に自動で作成するので、キャッシュ対象から外しておけば十分。
なお、bazeliskを使う場合は、bazeliskのキャッシュ自体も保存しておく必要がある。
jobs:
build:
runs-on: windows-2019
steps:
# ...
# bazeliskがダウンロードしてくる `bazel.exe` をキャッシュする
- name: Mount bazelisk cache
uses: actions/cache@v3
with:
path: C:\Users\runneradmin\AppData\Local\bazelisk
key: windows-bazelisk
- name: Mount bazel cache
uses: actions/cache@v3
with:
path: C:\_bzl
key: bazel-v1-cache
- run: |
bazel --output_user_root=C:\_bzl build ..
bazel --output_user_root=C:\_bzl shutdown
shell: cmd
# symlinkは `C:\_bzl\*\install` の1つ。これを削除しておく。
# 端的に、actions/cacheのpathで除外しても良いはず。
- run: |
(Get-Item C:\_bzl\*\install).Delete()
注意
弊プロジェクトだと、キャッシュなしのビルドに1時間程かかり、その間、キャッシュ対象が9GBまで膨れ上がり、tarにしてアップロードするのに40分前後かかります……(つまり、初回実行にかかる時間が、60分->100分に増える)。
キャッシュありだとビルドは瞬間的に終わりますが、キャッシュには保存期限があるので、頻繁に実行するのでなければキャッシュを有効にする意味はないです。
ただ、個人プロジェクトで、たまにしか作業しない時も、ブランチ切ってpushしてから作業に入れば、作業内容をpushした時にキャッシュが生きていて嬉しいかも。