タケユー・ウェブ日報

Webシステム受託会社の業務の中での気づきや調べごとのメモ。

graphql-ruby + Multiple Databases with ActiveRecord

Query では読み込み専用 、Mutation では読み書きを使うようにしたかった。

github.com

上記のコメントで動くのだが、テストでトランザクションを使ったロールバック戦略を採用していると、レプリカに変更が伝搬されずに失敗する点に注意。(関連:Rails 6.0の複数DBでリードレプリカのテストするのたぶん大変

module Tracers
  class DatabaseRoleTracer
    EVENT_NAME = 'execute_multiplex'.freeze

    def trace(event, data)
      # テストではテストケースごとにトランザクションをロールバックするためコミットされずレプリカに伝搬しない
      # ので、やむなくテストモードでは無効=プライマリに繋ぐ
      if event == EVENT_NAME && !Rails.env.test?
        multiplex = data[:multiplex]

        role = multiplex.queries.all?(&:query?) ?
          ActiveRecord::Base.reading_role :
          ActiveRecord::Base.writing_role

        Rails.logger.debug("[#{self.class.name}] ActiveRecord::Base.connected_to(role: #{role.inspect})")
        ActiveRecord::Base.connected_to(role: role) do
          yield
        end
      else
        yield
      end
    end
  end
end

class MyAppSchema < GraphQL::Schema
  mutation(Types::MutationType)
  query(Types::QueryType)

  # 省略

  # Query か Mutation かで接続先データベースを変更する
  tracer Tracers::DatabaseRoleTracer.new
end

railsguides.jp

graphql-ruby.org