santiago.pastorino

bundle exec rails … executes Bundler.setup 3 times

Posted by santiago.pastorino
on December 27, 2011

TL;DR: don't run bundle exec before rails command, rails already checks the presence of Bundler through the Gemfile and sets up everything according to it without the overhead of bundle exec. rails command is the only exception to the rule. Additionally I've added a patch to Bundler that avoids calling Bundler.setup which adds unnecessary overhead.

I was researching on a huge Bundler 1.1 performance regression, @masterkain was hitting when running bundle exec rails runner '' (you shouldn't run bundle exec before the rails command, but keep reading for now). I started to profile it using ruby-prof and one of the things I realized was that Bundler.setup (which is a considerable slow method because it calls Bundler::Runtime#setup) was ran 3 times. My first reaction was WTF?? 3 times??. I will write about my other findings in another blog post.

After analyzing the code, I found out that the first call to Bundle.setup is in Bundler::CLI#exec right before shelling out to run rails runner ''. The second call is on boot.rb as part of the boot process (well actually it's required from bundle exec through this rubyopt and on boot.rb the require returns false because it's already required). And the last call starts on config/application.rb which ends up calling Bundler.require to finally call Bundler.setup for the third time. The second and third calls are run on the same process so Bundler.setup caches the result in @setup so there's no slow down between those 2 calls. But the command passed to bundle exec runs in a different process (remember I said before that we were shelling out to run rails runner '') so the resulting execution of the first Bundler.setup won't be available to the rails runner process" and doesn't make any sense. All that bundle exec needs to do is to "setup the rubyopts needed to run the command you are passing to bundle exec. I've patched Bundler to do the right thing.

So don't run bundle exec before rails command, this command is already aware of Bundler and sets up everything according to what you have on your Gemfile. If you prepend bundle exec before rails command all you will be adding is overhead of opening another process from Bundler and executing useless code since rails already does the right thing.

You probably already know about that, but I've seen a lot of proficient Rails developers doing it.

Read more about the topic in Yehuda's blog

| |
comments powered by Disqus