We recently upgraded many of our services to Rails 5.2 which installs bootsnap
to make start-up faster. However, bootsnap
depends on caching data to the local file system and our production containers run with read-only file systems for security. So I decided to remove bootsnap
in production:
# Gemfile #... group :development, :test do gem 'bootsnap', '~>; 1.3' end #... # config/boot.rb #... require "bundler/setup" # Set up gems listed in the Gemfile. begin require "bootsnap/setup" # Speed up boot time by caching expensive operations. rescue LoadError # bootsnap is an optional dependency, so if we don't have it it's fine # Do not load in production because file system (where cache would be written) is read-only nil end
The code above makes two changes:
- It only loads
bootsnap
in:development
and:test
environments. When production images are created we exclude those environments from the bundle. - It fails gracefully if
bootsnap
isn’t loaded.
These changes were mostly based on a change that GitLab did to accomplish the same thing (although for different reasons). There was discussion on the bootsnap
issues about disabling it in production but the solution was much more convoluted. This is a nice simple change.
I’m not yet convinced that we should even be running bootsnap
. It’s stated purpose is to “Boot large Ruby/Rails apps faster”, but we try to keep services small. In one service I found the following differences:
With bootsnap
:
real 0m2.094s user 0m1.743s sys 0m0.353s
Without bootsnap
:
real 0m5.124s user 0m3.590s sys 0m1.527s
So while it does save 3 seconds I am not sure that makes that much of a difference to our daily life for development or testing.
I don’t think rescue LoadError is a good idea, but you are knowingly making an exception to happen and rescuing it
I don’t know of any other way to make an optional `require`. That is, to `require` a file only if a gem is loaded.
That said, I’ll point out that we’ve just removed bootsnap completely from our services, per the final comment. It’s not really making a big difference in performance for development and it clearly is buggy.
I know it’s like a year later, but you want:
require ‘bootsnap/setup’ if Gem.loaded_specs.has_key? ‘bootsnap’
in case it helps someone else:
require ‘bootsnap/setup’ if Gem.loaded_specs.has_key? ‘bootsnap’