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
andassets: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 runningrake -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
withoutassets:clean
- Re run justassets:precompile
, update the cache so it will eagerly check on next deploy and continue the build as normal - Does not have
assets:precompile
orassets:clean
update the cache so it will eagerly check on next deploy and continue the build as normal
- Has
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
.