Evaluating GitHub Actions

10 Likes

This will make life doing rollups so much better! :tada:

1 Like

Question: would you recommend switching rust-analyzer from Travis to Actions?

I am mostly a happy customer of Travis (it works), but I wonder if there are any reasons to justify the switch? Would actions be faster? Is it true that they don’t have build-in caching yet (I rely heavily on caching the subset of the target dir)?

Caching for GitHub Workflows was released just before GA: https://github.com/actions/cache

They provide Rust/Cargo examples:

- name: Cache cargo registry
  uses: actions/cache@v1
  with:
    path: ~/.cargo/registry
    key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
  uses: actions/cache@v1
  with:
    path: ~/.cargo/git
    key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
  uses: actions/cache@v1
  with:
    path: target
    key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

In terms of evaluating GitHub Actions for rust-analyzer, I'm happy to help set it up.

1 Like

I'm moving my own repos to it one at a time and the builds are faster even without caching in my case. I'm a bit curious to see what will be the speed difference with the new cache @CAD97 would be though! I remember an article some time ago showing that it was faster in some cases to not cache things even on Travis due to the cache size.

It might be because default caching of cargo on Travis is just not good (because cargo is not amendable to CI caching). You need some manual tweaking to make it a net benefit: https://github.com/rust-analyzer/rust-analyzer/blob/97a14d51edf810179472813dce6b4d47f8ff106b/.travis.yml#L4

I've found Travis to be very slow with large caches (although I haven't tried other platforms to compare against). On the crates.io repo we have a few workarounds to keep our cache sizes in check.

Before the build we run cargo-clean-on-new-rustc-version.sh, which puts a version stamp file in the cache and will run cargo clean if the version has changed. This keeps cruft from accumulating, especially on beta and nightly channels.

After the build (before_cache) we run prune-cache.sh which deletes any binaries/tests, which are large for us and unlikely to be reused between commits. (This probably isn't as generally applicable as the previous script.)

Even with these mitigations, we can end up with bloated caches when a deeply nested transitive dependency is bumped. This is most likely to affect us on the stable channel, as it can accumulate 6 weeks of changes before the next release.

I haven't looked into the buildpack yet, but it would be nice to have an easy way to manage the cache when deploying to Heroku as well.

By quickly glancing at crates.io CI, it looks like the cache is busted on every build:

I think this should not happen in an ideally configured travis cache (ie, travis is optimized for stable caches). Here's how this step looks in an average rust-analyzer build:

The difference is time is 3 minutes!

@matklad I've opened #1902 to try to improve this. I have a few repositories that always see changes to files under target/debug/incremental, and I'm not quite sure what is different in the rust-analyzer repo that avoids that. The PR now manually deletes the incremental directory and target/.rustc_info.json and that helped reduce the cache size (with some increase to clippy and build times).

Even with these improvements, I'm now seeing changes to files under /home/travis/.cargo/registry/index/github.com-1ecc6299db9ec823/.cache/ (log). I'm not sure what this directory is used for, and locally these files don't seem to change with each build. If anyone has suggestions, please let me know over on that PR.

Setting CARGO_INCREMENTAL to zero should help both with making caches more stable and smaller: https://github.com/rust-analyzer/rust-analyzer/blob/d0357fc3b270d5b05665395b95958ac2a3d1c51a/.travis.yml#L20

I am actually not sure why cargo uses incremental in your case: I think it is disabled by default on CI?

Could you elaborate on the advantages of Github Actions over Azure Pipelines that made you consider the switch? I'm asking because I moved a project (Lean 4, for context) over from Travis+AppVeyor to Pipelines just before Actions was announced, so now I'm wondering if I should follow your example again.

AFAIK, the Actions runner and actions were forked from Pipelines, so I assume the differences there are less significant. If it is really all about better UX right on Github, I think I can empathize with that. I always felt that I needed too many clicks to navigate from Github to the log of a failing build on Pipelines.

Yeah, the main motivations were not having to deal with a separate set of accounts and permissions, and in general the solution being more integrated with GitHub's UI. The other motivation that only affects us is that it's easier for technical reasons for Microsoft and GitHub to provide us an hosted builder pool with increased resources on GitHub Actions rather than Azure Pipelines.

5 Likes

Another thing to note: GitHub action's cache size is capped at 400mb for each tarball uploaded.

3 Likes