Kaigi on Rails 2025 に参加した Kaigi Effect で ActiveRecord のコネクションを一定期間で再接続するだけの Gem を作った

タイトルが長い。そしてタイトルで全て語ってしまった。

経緯

Day 1 のこちらのセッションを拝聴させてもらいました。

kaigionrails.org

途中 X に投稿したポストの会話が以下。

RailsとAmazon Aurora利用時のフェイルオーバー問題

koyaさんが言及している記事に書いてある通りなので説明はそちらに譲るとして、自分が携わっているプロダクトでも最近この話題があって気になってました。

DBMS が特定されていれば、入れ替わった時に発生するエラーは識別可能なのでそれを検知して再接続すればいいのはそれはそう。とは言えもっと統一的な解決策はないものかとここ数日考えていました。

以下のような話もある。

discuss.rubyonrails.org

これはフェイルオーバー問題そのものではないが、接続期間の Lifetime を設けてみてはどうかという機能提案。議論は進んでなさそうではある。

コアの実装を変更せずに Lifetime を実現する PoC

さて AbstractAdapter には checkout と checkin のコールバックが設定できるようになっている(checkout と checkin の概念とは何かという話は割愛、ActiveRecord::ConnectionAdapters::ConnectionPool のソースコードを読んでみよう!)。これを利用することで Lifetime 的なものを実現できるのではないかと思い付いた。

  ActiveRecord::ConnectionAdapters::AbstractAdapter.set_callback(:checkout, :after) do
    reconnection_interval = @config[:reconnection_interval]
    next unless reconnection_interval

    @window_start_at ||= Process.clock_gettime(Process::CLOCK_MONOTONIC)
    if (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @window_start_at) > reconnection_interval
      reconnect!
      @window_start_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    end
  end

例えば database.yml で reconnection_interval を秒数で設定するという思想。ポイントとしては @config[:reconnection_interval] から値を取得するところで、例えばアプリケーションが複数データベースに接続している場合、あるデータベースには5秒で再接続としたいが別のデータベースには30秒で再接続したい、といったことがこれで実現できる。(と思っている。おいおいちゃんと検証する)

試してみる

rails console で試してみる。TracePoint を使って reconnect メソッドが呼ばれているかを確認してみよう。database.yml は以下のように設定する。

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  reconnection_interval: 5

TracePoint の設定はこんな感じ。

trace = TracePoint.new(:call){|tp|puts "[#{tp.event}] #{tp.defined_class}##{tp.method_id}" if tp.defined_class&.to_s&.include?("SQLite3Adapter")&&tp.method_id&.to_s&.include?("reconnect")}.tap{|trace|trace.enable}

やってみた。

せっかくなので Gem にしてみた

というわけでこれ。

github.com

実装は前述したコールバックを設定する実装だけなので config/initializer あたりにコピペするだけでもいいんだけど、Gem として公開されていれば GitHub Issues にどういった問題があったのかということが記録として残せるでしょうという魂胆です。

おわりに

Kaigi Effect しました!ちなみにこのブログ記事は Day 2 中に書いてます。まだまだ Kaigi on Rails 2025 楽しみましょう!