LoginSignup
10
10

More than 5 years have passed since last update.

規約から外れた接続先を見るモデルを含む場合のOctopusによるreplication

Posted at

Octopusというライブラリを用いるとActiveRecordでsharding/replicationが実現できる。

DB構成

ユーザデータを持つDB

ホスト: userdb.localhost
データベース名: user
replication: しない (アプリケーションでは読み取りしかしないので最初からslaveのみ参照するようになっている)

アプリケーションのデータを持つDB

ホスト: app.localhost
データベース名: app_{RAILS_ENV}
replication: する

何が問題か

OctopusがActiveRecord::Base#connectionActiveRecord::Base#connection_poolを乗っ取って、クエリを監視して適宜、shardもしくはmaster/slaveへ投げるようになる。

Octopusを使ってreplicationをする設定 (config/shards.ymlにreplicated: true) の場合、masterはconfig/database.yml, slaveはconfig/shards.ymlを見る。

replicationをしたくない場合 (config/shards.ymlにfully_replicated: false) であっても、Octopusがクエリ監視をするため、モデルで個別の接続先を指定していてもOctopusが上書きしてしまう。

対処法

目には目を、歯には歯を、メタプログラミングにはメタプログラミングを。

alias_method_chainで上書きしている。 (cf. lib/octopus/model.rb:L80)

alias_method_chain(original_method, feature_name){original_method}_with_{feature_name}{original_method}_without_{feature_name}というメソッドを定義する。

{original_method}_without_{feature_name}がオリジナルの実装なのでこれをさらにaliasすればよい。

user.rb
class User < ActiveRecord::Base
  if defined?(Octopus::Model::InstanceMethods) && self < Octopus::Model::InstanceMethods
    alias_method :connection, :connection_without_octopus
    alias_method :connection_pool, :connection_pool_without_octopus
  end

  establish_connection("user_db_#{Rails.env}")
  self.table_name = :user
end
10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10