Space Vatican

Ramblings of a curious coder

environment.rb and Requiring Dependencies

In the before time, the bottom of most of my apps’ environment.rb was an unholy mess. Inflector rules, requiring of various libraries or gems, various bits of app specific configuration etc… all jumbled together. Rails 2.0 introduced initializers: any file in config/initializers is run at an appropriate time during the initialisation process. You get to split that mess into a handful of well organised, single purposed little files (and rails 2.1 simplified the case of requiring gems with the config.gems mechanism).

You might still have a few stragglers though, that one require that you didn’t bother moving into an initializer because it hardly seemed worth creating a whole file just for that one line. With the imminent release of Rails 2.2 it’s high time you made that change.

Living Thread Dangerously

Unless you’ve been living under an internet-proof rock you’ve probably heard about Rails’ new threadsafeness. There’s a bunch of hard work across the framework that’s gone into making this possible, but one particular area is to do with loading code. Ruby’s require mechanism isn’t threadsafe (or as it has been put to me, it’s thread dangerous) nor is the automatic loading stuff Rails’ uses. For example say two threads both hit a constant called Foo that has yet to be loaded. Thread 1 starts loading foo.rb and gets as far as

class Foo < ActiveRecord

At this point Thread 2 hits Foo. However at this point the constant Foo now exists and so Thread 2 doesn’t load foo.rb. However since Thread 1 hasn’t yet processed the rest of foo.rb the Foo class will be missing all its instance methods, validations etc… If both threads end up loading foo.rb at the same time then weird things can happen like validations being added twice and so on. It can also cause the dependencies system to spuriously claim it couldn’t find a constant. It’s a small world of pain you don’t want to get involved in. Making require threadsafe is fundamentally hard (and is something the ruby-core and jruby folks have been worrying about).

What Rails 2.2 does in production mode is load all of your models, controllers and so on as part of the initialization process instead of loading them as they are needed. No more loads from different threads when your app is actually running, no more pain.

The Bad Thing

So, how does this connect with the statement I made above about moving things into initializers? Your average environment.rb file looks a little like this

#set some constants like RAILS_GEM_VERSION
require File.join(File.dirname(__FILE__), 'boot') do |config|
  #set some config settings
#if you're old school, app configuration here
require 'some_dependency'

The bulk of initialization happens when you call run. This yields to the block to allow you to set the various settings (and also reads the appropriate environment file and so on) but the key thing is that by the time that function has returned, all of the initialization has happened.

In particular, Rails will try to load all of your application classes before the stuff at the bottom of environment.rb has been executed. If a model depends on some_dependency.rb being loaded (for example if that file added a validation that it uses) then your app will die before it even finished initialising.

If however you’re a good person and move these things into initializers (i.e. files in config/initializers) then they will run at an appropriate time in the boot process (i.e. before Rails loads up all your application classes) and you won’t get an unpleasant surprise when you try and deploy your app.