Rails Autoloading: cleaning up the mess

Just when I thought I understood Rails autoloading, it threw two more curve balls at me.

Managing Database Connections with to_cleanup

When a database application is running along nice in production, you don’t want to be creating and destroying connections all the time. ActiveRecord and company can handle this easily in development because they are library code, which doesn’t get reloaded between requests.

I, however had a rails-independent library. It started out as database conversion, so I used Sequel, which allowed me to throw hashes at the database without undue ceremony (other than setting up a schema) Eventually, a query got added as well, with a database connection kept around as a class variable.

Problem: when the class gets unloaded, the reference to the connection gets lost, but not actually disconnected. Not only does the app have to connect again (minor) but the database eventually runs out of connections, and my app gets an exception. (In the case of Postgres, PGError: FATAL: sorry, too many clients already)

Fortunately, we can hook into the reloading process and request to be disconnected beforehand. Reloading appears to be managed by ActionDispatch::Reloader, which has a to_cleanup method. Pass it a block to be run during the unloading process.

This is a delicate procedure. Putting in a config/initializers/ doesn’t work because it gets scheduled after the cleanup method that actually unloads the classes – it will reload the class and then not find a database connection to disconnect. The call actually has to appear in development.rb or another suitable early place in order to get a chance at the connection before the class’s untimely demise.

ActionDispatch::Reloader.to_cleanup {Thingy.disconnect}

(There is no magic to disconnect, it’s a method I wrote.)

Class Configuration with to_prepare

A common pattern for configuring Ruby code is to set properties on a class or module. (I’m actually starting to distrust this – it’s shared global state – but we’ll roll with it for now.)

Problem: when Rails unloads the classes, the configuration gets lost. The settings work once, and then disappear on the next request.

Fortunately, ActionDispatch::Reloader also has a to_prepare method that gets called before each request. For the price of putting my code in a block that gets re-run every time (it’s only in development.rb after all), I can ensure that the parameters are set every time.

ActionDispatch::Reloader.to_prepare do
  Thingy.perform_timing = true
end
Posted Friday, December 30th, 2011 under Essay.

Comments are closed.