Just when I thought I understood Rails autoloading, it threw two more curve balls at me.
Managing Database Connections with
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.
(There is no magic to disconnect, it’s a method I wrote.)
Class Configuration with
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.
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