Skip to content
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

Tenant.switch! raises exception on first call / Postgresql #92

Closed
mtnstar opened this issue Jul 15, 2020 · 7 comments · Fixed by #95
Closed

Tenant.switch! raises exception on first call / Postgresql #92

mtnstar opened this issue Jul 15, 2020 · 7 comments · Fixed by #95
Labels
bug Something isn't working

Comments

@mtnstar
Copy link

mtnstar commented Jul 15, 2020

Steps to reproduce

In rails production env: Apartment::Tenant.switch!('public')

Expected behavior

it changes current tenant to public.

Actual behavior

raises an exception when trying to switch to any tenant.

Caused by:
PG::ConnectionBad: FATAL:  database "public" does not exist
/opt/app-root/src/bundle/ruby/2.5.0/gems/pg-1.2.3/lib/pg.rb:58:in `initialize'
/opt/app-root/src/bundle/ruby/2.5.0/gems/pg-1.2.3/lib/pg.rb:58:in `new'
/opt/app-root/src/bundle/ruby/2.5.0/gems/pg-1.2.3/lib/pg.rb:58:in `connect'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/postgresql_adapter.rb:46:in `postgresql_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:887:in `new_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:931:in `checkout_new_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:910:in `try_to_checkout_new_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:871:in `acquire_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:593:in `checkout'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:437:in `connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:1119:in `retrieve_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_handling.rb:221:in `retrieve_connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activerecord-6.0.3.2/lib/active_record/connection_handling.rb:189:in `connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/railtie.rb:39:in `connection'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:184:in `connect_to_new'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:76:in `block in switch!'
/opt/app-root/src/bundle/ruby/2.5.0/gems/activesupport-6.0.3.2/lib/active_support/callbacks.rb:101:in `run_callbacks'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:75:in `switch!'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:88:in `switch'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:102:in `block in each'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:101:in `each'
/opt/app-root/src/bundle/ruby/2.5.0/gems/ros-apartment-2.7.1/lib/apartment/adapters/abstract_adapter.rb:101:in `each'

System configuration

  • Database: Postgresql 9.5.14

  • pg gem: 1.2.3

  • OS: Linux / Docker

  • Apartment version: 2.7.1

  • Apartment config (in config/initializers/apartment.rb or so):

    • config.use_schemas = true
  • Rails (or ActiveRecord) version: 6.0.3.2

  • Ruby version: 2.5.5

@mtnstar mtnstar changed the title Tenant.switch! 'public' / Postgresql, pg gem 1.2.3 Tenant.switch! raises exception on first call / Postgresql, pg gem 1.2.3 Jul 15, 2020
@mtnstar mtnstar changed the title Tenant.switch! raises exception on first call / Postgresql, pg gem 1.2.3 Tenant.switch! raises exception on first call / Postgresql Jul 15, 2020
@codez
Copy link

codez commented Jul 15, 2020

This happens when .connection is called before the rails application is initialized. Tenant.init_once delegates to adapter.init. However, the correct adapter (Adapters::PostgresqlSchemaAdapter) is only used after rails initialization. Because the adapter is further cached in Thread.current, it is not replaced anymore.

Probably, replacing Apartment::Tenant.reinitialize with Apartment::Tenant.reload! in the Railties to_prepare block would help?

@rpbaltazar rpbaltazar added the bug Something isn't working label Jul 16, 2020
@rpbaltazar
Copy link
Contributor

@psunix in which moment are you calling Apartment::Tenant.switch!('public') ?
I'm having some issues reproducing the error on my end. We use postgresql and all our envs work correct (The typical it works on my machine).

I'm still trying to find out what's the best info you can provide for me to simulate your use case, so for now, if you can reproduce the error in a sample app that would be awesome.

@rpbaltazar
Copy link
Contributor

@codez what you're saying I think partially makes sense. Though, reload! internally calls reinitialize so I don't really see how would that help.

@fsateler do you mind chipping in since you've worked on this refactor?

@mtnstar
Copy link
Author

mtnstar commented Jul 16, 2020

@rpbaltazar thx for your help.

we're calling switch inside our gem for checking if all migrations have completed: https://github.com/puzzle/bleib/blob/master/lib/bleib/migrations.rb#L62

I think it's a special situation here. @codez was able fixing it be first calling Apartment::Tenant.reload! in the rake task we use to check if all migrations have completed.

@codez
Copy link

codez commented Jul 16, 2020

In that gem, we actually call ActiveRecord::Base.connection in a rake task before the rails application is initialized. Therefore, the apartment configuration, which happens in an initializer, is not executed yet.

Because of

def connection
, the adapter is already created and stored in Thread.current. Calling reload!would nilify Thread.current, so the correct adapter would be chosen on the subsequent initialization.

@rpbaltazar
Copy link
Contributor

@psunix and @codez thank you for the detailed info on your use case.
The way you put it, @codez totally makes sense. I'll give it a go and see if that change does not break any current test. I'll try to write a test case for that as well, though i'm not sure right now how would i go about it.

@codez
Copy link

codez commented Jul 16, 2020

Wow, that was fast. Thank you very much for the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants