Concurrency issues with choosing a specific database connection based on user with Rails ActiveRecord / PostgreSQL

I have a setup where a Rails 5 / Ruby 2.4.1 application requires a connection to two databases, both on one PostgreSQL instance and on all users, selected based on authenticated user. Both databases combine a connection pool of 5 connections.

I am using the base ActiveRecord classes for both cases, something like

class Base1 < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "base1_#{Rails.env}".to_sym
end
class Base2 < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "base2_#{Rails.env}".to_sym
end

      

In order to dynamically select the database for each user, I have a before_action block in the ApplicationController doing

dbconf = Base2.configurations[Rails.env].dup
dbconf['database'] = current_user.db
Base2.establish_connection(dbconf)

      

This seemed to work under Rails 4.2 for every request model, but after migrating to Rails 5 / Puma, I get occasional errors when requests related to classes inherited from Base2 fail. Puma must run with at least two threads, and requests must occur in parallel for an error to occur. Some debugs show that Base2ChildClass.connection.current_database is the one specified for Base1.

Is this some (almost) known bug in merging ActiveRecord connections? Is my db switch approach valid? I would understand if thread safety violations would mix different db instances in Base2, but how do the Base2 base classes actually get the Base1 connection in their hands?

+3


source to share





All Articles