ActiveRecordを複数スレッド環境で利用する

ActiveRecordを何も考えずに複数スレッドが動作する環境で利用すると、スレッド毎にActiveRecordがコネクションを確保しようとするので、プールサイズを超えてコネクションが確保できないというエラーが発生する。

activerecord-4.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:190:in `block in wait_poll': could not obtain a database connection within 5.000 seconds (waited 5.001 seconds) (ActiveRecord::ConnectionTimeoutError)

こちらとしてはコネクションプールがあるのだから、ActiveRecordの方でやりくりをしてよろしくやって欲しいのだが、どうもそういう挙動ではないようだ。

そのようなときには、ActiveRecord::ConnectionAdapters::ConnectionPool#with_connectionメソッドを利用するとよい。具体的には次のように書く。

require 'active_record'
require 'pg'

ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.establish_connection(adapter:  'postgresql',
                                        host:     'localhost',
                                        database: 'blog',
                                        pool:     1)
class Post < ActiveRecord::Base
end

2.times.map {
  Thread.new do
    ActiveRecord::Base.connection_pool.with_connection do
      Post.take
    end
  end
}.map(&:join)