-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Discussion] Has anyone tired using Postgres with multiple databases holding multiple tenants/schemas? #206
Comments
@JonMcCarthy7 We have been using this in production for ~5 years. At this point we have >100 tenant databases with 1-5gb of data per database. I honestly consider this architecture decision one of the worst in my career. By all metrics we have 'successfully' accomplished this architecture, however it is turning into a major issue as we look forward to scaling and re-factoring our codebase. Backing out of this style multi-tenant database is a HUGE problem. Be advised. For your specific issue, if you find yourself switching between multiple tenants per request or per lifecycle of a thread, you probably need to reconsider how you are separating data. You should definitely be looking at expanding thread pools and minimizing the amount of switching per request that you are performing. |
Hey @SkyM. Thanks for the response. Are you saying you did the 1 Tenant per DB approach? Sorry if I wasn't clear, in my case I'm trying to set up multiple tenants on each database/shard. |
We used MySQL and did one tenant per database with a master database to handle shared data. |
For context, you may want to read through this discussion on the original library: influitive/apartment#636 |
We have been using the
If you have the same use case, this setup with apartment gem and PostgreSQL with a separate schema for each tenant will work like a charm:
But there are use cases when this setup would not be beneficial:
|
Sorry, I realized we use multiple DBs with tenants differently than you asked. In our case, we have multiple DB servers and use separate schemas for each tenant. But we keep all the tenants on each of DBs. This means we have schema "test-client-1" on all DB servers. But "DB server 1" has tables dedicated to one business domain and "DB server 2" has tables dedicated to another business domain. Each worker keeps a connection to all DBs and switches between tenants with our custom |
I am experimenting with multiple DB Hosts [#208]. I am experiencing a lot of issues. You mention a custom irb(main):007:0> Apartment.tenants_with_config
=>
{"tenant_1"=>{"adapter"=>"postgresql", "host"=>"localhost", "port"=>5432, "encoding"=>"unicode", "database"=>"development"},
"tenant_2"=>
{"host"=>"some-host-ip",
"adapter"=>"postgresql",
"database"=>"tenant2_db",
"username"=>"postgres",
"port"=>5432,
"encoding"=>"unicode",
"password"=>"[redacted]"}} irb(main):006:0> Apartment::Tenant.switch('tenant_2')
/Users/tom/.rbenv/versions/3.0.4/lib/ruby/gems/3.0.0/gems/ros-apartment-2.11.0/lib/apartment/adapters/postgresql_adapter.rb:139:in `raise_schema_connect_to_new': Could not set search path to schemas, they may be invalid: "tenant_2" "tenant_1". (Apartment::TenantNotFound)
Original error: ActiveRecord::StatementInvalid: Could not find schema tenant_2
/Users/tom/.rbenv/versions/3.0.4/lib/ruby/gems/3.0.0/gems/ros-apartment-2.11.0/lib/apartment/adapters/postgresql_adapter.rb:75:in `connect_to_new': Could not find schema tenant_2 (ActiveRecord::StatementInvalid) The odd thing is if I issue a irb(main):008:0> Apartment::Tenant.drop('tenant_2')
(90.3ms) DROP SCHEMA "tenant_2" CASCADE
=> #<Thread::ConditionVariable:0x000000010baf2510> |
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
end
class Db1Base < ApplicationRecord
self.abstract_class = true
establish_connection(:db1)
end
class Db2Base < ApplicationRecord
self.abstract_class = true
establish_connection(:db2)
end
class ModelMain < ApplicationRecord; end
class Model1 < Db1Base; end
class Model2 < Db2Base; end module SwitchTenant
def self.reset
switch!(Apartment.default_tenant)
end
def self.switch!(tenant = nil)
if tenant.nil?
reset
else
# Main DB
Apartment::Tenant.switch!(tenant)
# DB1
Db1Base.connection.schema_search_path = tenant
Db1Base.connection.clear_query_cache
# DB2
Db2Base.connection.schema_search_path = tenant
Db2Base.connection.clear_query_cache
end
end
def self.switch(tenant = nil)
switch!(tenant)
yield
ensure
reset
end
end
|
I'd like to hear from people who have been able to successfully accomplish this type of architecture using this gem. I'm currently stuck with connection errors from constantly switching database connections. I think the route I need to take is better managing the connection_handler/connection_pools that connect to each database. Has anyone ran into something similar? Thanks
The text was updated successfully, but these errors were encountered: