Rails ActiveRecordをマルチスレッドで使う

スポンサーリンク

マルチスレッド環境で Rails の ActiveRecord を使おうとしたところ、以下のエラーに遭遇しました。スレッド毎に、ActiveRecord がDB接続(コネクション)を確保しようとするために、コネクションのプールサイズをオーバーしてしまうのが原因です。

— 環境 —
Rails 4.2
Ruby 2.3

【お知らせ】 英単語を画像イメージで楽に暗記できる辞書サイトを作りました。英語学習中の方は、ぜひご利用ください!
画像付き英語辞書 Imagict | 英単語をイメージで暗記
【開発記録】
英単語を画像イメージで暗記できる英語辞書サービスを作って公開しました
スポンサーリンク

エラーが発生したコード

スレッド毎に User モデル(データベースの users テーブル)を検索して、結果を後で user_groups としてまとめるようなコードを書いていた。

User.first_group, User.second_group は、それぞれ特定の条件で User モデルを検索する scope です。この書き方だと ActiveRecord::ConnectionTimeoutError が発生します。

ActiveRecord::Base.connection_pool.with_connection を使う

ActiveRecord::Base.connection_pool.with_connection を使って、そのブロック内でモデルを検索するようにコードを修正することで、ActiveRecord::ConnectionTimeoutError を解決できます。

ActiveRecord::Base.connection_pool.with_connection のソースを読んだところ、fresh_connection(新規のDBコネクション)の場合、ブロック実行後に ensure 節で release_connection(コネクションを解放)するコードとなっています。次の説明が書いてありました。

Use ActiveRecord::Base.connection_pool.with_connection(&block), which obtains a connection, yields it as the sole argument to the block, and returns it to the pool after the block completes.

意訳)ActiveRecord::Base.connection_pool.with_connection(&block) を使うと、コネクションを取得して、そのコネクションをブロック引数としてブロックを実行し、ブロック実行が終了したらそのコネクションをプールに戻します。

ということで、ActiveRecord::Base.connection_pool.with_connection に渡すブロック内で、User モデルを検索するようにコードを変更しました。

これでエラーが発生しなくなりました。

スポンサーリンク
パーフェクト Ruby on Rails は、最近読んだ Rails 本の中では一番役に立った本です。Chef や Capistrano など Rails と共によく使用される技術にも触れてあります。Ruby on Rails 4 アプリケーションプログラミングは、入門的な内容で Rails の機能全体を網羅されています。
 
スポンサーリンク

Leave Your Message!