heroku / heroku/buildpacks-ruby
Cache `bundle list` and `rake -P`
- Dominant language
- Rust
- Stars
- 30
- Forks
- 7
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 5
Description
Deploying with a cached CNB is fast. Really fast. But it could be faster. Right now it takes about 6 seconds (below). I think we could make it faster if we skip running `bundle exec rake -P` (1.5~3 seconds) and `bundle list` (~0.3s). Here's an example output, and below I'll explain the logic that I think allows us to safely skip these:
```
# Heroku Ruby Buildpack
- Metrics agent
- Skipping install (`gem 'barnes'` not found in Gemfile.lock)
- Ruby version `3.1.3` from `Gemfile.lock`
- Using cached version
- Bundler version `2.4.7` from `Gemfile.lock`
- Using cached version
- Bundle install
- Loading cache
- Skipping `bundle install` (no changes found in /workspace/Gemfile, /workspace/Gemfile.lock, or user configured environment variables)
- ! HELP To force run `bundle install` set `HEROKU_SKIP_BUNDLE_DIGEST=1`
- Setting default processes(es)
- Running `bundle list` ... (0.313s)
- Detected rails app (`rails` gem)
- Rake assets install
- Rake detected (`rake` gem found, `Rakefile` found ad `/workspace/Rakefile`)
- Running `bundle exec rake -P --trace` ...... (3.038s)
- Compiling assets with cache (detected `rake assets:precompile` and `rake assets:clean` via `bundle exec rake -P`)
- Loading cache for /workspace/public/assets
- Loading cache for /workspace/tmp/cache/assets
- Running `bundle exec rake assets:precompile assets:clean --trace`
** Invoke assets:precompile (first_time)
** Invoke assets:environment (first_time)
** Execute assets:environment
** Invoke environment (first_time)
** Execute environment
** Execute assets:precompile
** Invoke assets:clean (first_time)
** Invoke assets:environment
** Execute assets:clean
- Done (2.030s)
- Storing cache for /workspace/public/assets
- Storing cache for /workspace/tmp/cache/assets
- Done (finished in 6.188s)
```
## Skipping Bundle list
If the `bundle install` step is skipped, we can use the same metadata to skip the `bundle list` step, and use the same `HEROKU_SKIP_BUNDLE_DIGEST` to force this to run.
## Skipping `rake -P`
This is trickier as someone could delete all the code in their Rakefile and we wouldn't catch it without this task. I think my logic looks like this:
- If both `assets:precompile` and `assets:clean` are found in the last run (store in the metadata) then assume both of them continue to exist and run the tasks without first running `rake -P`
- PASS: Do nothing, continue on with the program execution, we guessed correctly
- FAIL: Re-run the `rake -P` check.
- If those tasks did exist then we already ran them and they failed, so fail the build
- If those tasks no longer exist, then move forward accordingly
- Has `assets:precompile` without `assets:clean` - Re run just `assets:precompile`, update the cache so it will eagerly check on next deploy and continue the build as normal
- Does not have `assets:precompile` or `assets:clean` update the cache so it will eagerly check on next deploy and continue the build as normal
This is essentially a try-catch strategy. I believe for the most common case (tasks existed last deploy and still exist today) that this is a decent strategy.
We need some kind of way to turn it off. Possibly `HEROKU_SKIP_RAKE_TASK_CACHE=1`.
Contributor guide
Assessment
This issue has not been assessed yet.