しゅがーブログ

技術ネタとか書いていけたらな…

【MongoDB】Passengerプロセスがリコネクトできない時の対処方法

Overview

MongoDBのPrimaryを切り替えたときにPassengerプロセスが切り替わったPrimaryへ接続できなかったのでそのときのまとめです。

環境

MongoDB: 3.6
mongoid: 6.4.2
Ruby MongoDB Driver: 2.8
Rails: 5.2

なぜリコネクトできないのか

公式リファレンスによると、、、

When a process forks, Ruby threads are not transfered to the child processes and the Ruby driver Client objects lose their background monitoring. The close/reconnect pattern described here should be used with Ruby driver version 2.6.2 or higher. Previous driver versions did not recreate monitoring threads when reconnecting.

子プロセス側に監視スレッドが引き継がれないので、フォーク時にリコネクトするようにし子プロセス側でも監視スレッドが立ち上がるよう対応してね、ということみたい。

追加する設定

Passengerの場合はこんな感じに書く
config.ruconfig/application.rb のようなアプリケーション起動時に読み込まれるファイルへ記述すること。
※ 久しぶりに見るとpassengerの設定も追加されていた。

if defined?(PhusionPassenger)
  PhusionPassenger.on_event(:starting_worker_process) do |forked|
    if forked
      Mongoid::Clients.clients.each do |_name, client|
        client.close
        client.reconnect
      end
    end
  end
end

実際にPrimary切り替え

事前にレプリカセットを組んでいることが前提です。

Primaryへログインしmongo shellを起動し、priorityをどのノードよりも高く設定します。

$ mongo データベース名
> conf = rs.conf()
> conf.members[0].priority = 128
rs.reconfig(conf)

切り替え後にアプリケーションログを見てみると、正常に切り替わり後続処理が問題なく完了していることが確認できると思います。

まとめ

上記設定を追加後にPrimaryを切り替えてみると、問題なくリコネクトできていることが確認できると思います。
もちろん書き込み先が変わるのでわずかに書き込みエラーは発生しますが、読み込みエラーなどは限りなく少なくなります。