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

Flexible switching #1

Open
wants to merge 26 commits into
base: development
Choose a base branch
from
Open

Flexible switching #1

wants to merge 26 commits into from

Conversation

mikecmpbll
Copy link
Owner

No description provided.

Mike Campbell and others added 11 commits June 15, 2017 12:45
When the gem is initialised and a schema adapter is being used, the
adapter will initialise the schema_search_path which involves
touching the database, and thus checking out a connection for the
current thread. For threaded web servers, it is not expected that
the main thread has a database connection, so you typically set the
connection pool size equal to the number of web server threads.

This patch checks the connection back in to the pool after init so
that a web server thread can pick it up and use it.
* Use public_suffix for smarter subdomain parsing

* Check validity of domain and add tests for localhost and IP

* Remove unnecessary TLD length test
This is a complete rewrite of the adapters & of the test suite.

- Test suite rewritten in minitest
- Adapters handle separate physical tenant hosts seamlessly
- Supports Rails 5.1 and above only
- Dropped all adapters other than PG and MySQL (didn't get time, will
  accept PRs)
- Added 'tenant resolvers' for generating full database
  configurations from tenant names
- Added `tenant_decorator` option for using a proc to decorate your
  tenant database/schema names with Rails.env or anything else
- All excluded models share a connection pool
- All adapters & switching strategies are threadsafe
Still some issues around multithreading, I'm not confident it's correct.
Need to improve tests and fix postgresql database drop problem :/.
Use a Thread local in the connection_specification_name to isolate
each thread's connection config.
@rubendinho
Copy link

@mikecmpbll - is this PR meant to resolve issues like influitive#615 and influitive#311?

Looking to use Apartment with Puma and Postgres connection-switching, and running into issues running tests.

@mikecmpbll
Copy link
Owner Author

That right, yep. A lot has happened recently actually. We’ve been using this branch in production across multiple hosts, using threads, and serving approximately 50-100 requests per second, for about three weeks now. We’ve not experienced any major issues so far. We’ve fixed a number of small bugs over the last week or two.

@cgratigny
Copy link

@mikecmpbll this is really hopeful for what I'm doing, having threadsafe issues with Rails 6 + Postgres.

Do you have any example for what you are running instead of rake db:drop?

On development we often will do db:drop, db:create, db:migrate but the drop of course says not implemented.

@mikecmpbll
Copy link
Owner Author

hey @cgratigny . the postgres adapter isn't as well tested as the mysql which i use in production, although i did attempt to replicate all the existing tests for pg. because there's two ways to separate tenents on pg (schemas and databases), there's two methods drop_database and drop_schema.

there's no config option anymore for whether you're using schemas or databases and you can use both at the same time, so i guess there's no way for apartment to know whether you're trying to drop the tenant's database or schema without explicitly calling one of those methods.

not sure what the best approach should be for the drop method.

@rubendinho
Copy link

@mikecmpbll - Thanks so much for putting in so much work into this project. Do you have plans to eventually merge this PR into the main Apartment repo? If so, any idea when that might happen? We're deciding between schema-based and connection-switching approaches (Rails 6 + Postgres + Puma), so any ETA would be super helpful before we commit to one of the approaches.

@cgratigny
Copy link

@rubendinho I have a very strong interest in making this work with Postgres and database switching, we are limping along the best we can with some hacks.

@mikecmpbll
Copy link
Owner Author

mikecmpbll commented Oct 14, 2019 via email

@cgratigny
Copy link

@mikecmpbll I'm willing to contribute to the Postgres database side of things, test etc.

@mikecmpbll
Copy link
Owner Author

mikecmpbll commented Oct 14, 2019 via email

@rubendinho
Copy link

@mikecmpbll and @cgratigny - our use-case requires physical data separation (PG schemas are not sufficient), and I'd also be happy to contribute to the PG side of things, including using Heroku's API to manage database provision, if that's of interest to folks.

@mikecmpbll
Copy link
Owner Author

@mikecmpbll Any reason the first_subdomain elevator was removed here?

because it was no different to the other subdomain elevator as far as i could tell.

i've forked our active branch here; https://github.com/cpoms/innkeeper and released to rubygems https://rubygems.org/gems/innkeeper. i've not fully tested it after renaming the whole thing.

@cgratigny
Copy link

@rubendinho great! The of side needs some love on this for sure. I'll be physically separating in the future as well, just not there yet.

I'm not on Heroku but know a lot of people use it.

@NeelTandel-BTC
Copy link

@mikecmpbll any update regarding this #PR?

@pradeepibz
Copy link

Hi @mikecmpbll - I'm using this gem from your branch 'flexible-switching' in my old application got some compatible version issue.

My Dependencies:
Rails - 5.1.4
Ruby - 2.3.3

My errors when tried to do the bundle update:

Bundler could not find compatible versions for gem "actionmailer":
In Gemfile:
exception_notification was resolved to 4.4.3, which depends on
actionmailer (>= 4.0, < 7)

rails (~> 5.1.5.rc1) was resolved to 5.1.5.rc1, which depends on
  actionmailer (= 5.1.5.rc1)

Bundler could not find compatible versions for gem "actionpack":
In Gemfile:
axlsx_rails was resolved to 0.6.1, which depends on
actionpack (>= 3.1)

haml-rails was resolved to 2.0.1, which depends on
  actionpack (>= 5.1)

rails (~> 5.1.5.rc1) was resolved to 5.1.5.rc1, which depends on
  actionpack (= 5.1.5.rc1)

rspec-rails (~> 3.6) was resolved to 3.9.1, which depends on
  actionpack (>= 3.0)

Bundler could not find compatible versions for gem "activerecord":
In Gemfile:
apartment was resolved to 2.0.0, which depends on
activerecord (>= 5.2.0)

rails (~> 5.1.5.rc1) was resolved to 5.1.5.rc1, which depends on
  activerecord (= 5.1.5.rc1)

Bundler could not find compatible versions for gem "acts_as_list":
In Gemfile:
acts_as_list

Bundler could not find compatible versions for gem "json":
In Gemfile:
json (~> 1.8, >= 1.8.3)

instagram_graph_api was resolved to 0.0.10, which depends on
  koala was resolved to 3.0.0, which depends on
    json (>= 1.8)

link_thumbnailer was resolved to 3.4.0, which depends on
  json (>= 1.7.7)

sendinblue was resolved to 2.4, which depends on
  json

Bundler could not find compatible versions for gem "listen":
In Gemfile:
listen (>= 3.0.5, < 3.2)

spring-watcher-listen (~> 2.0.0) was resolved to 2.0.1, which depends on
  listen (>= 2.7, < 4.0)

Bundler could not find compatible versions for gem "rails":
In Gemfile:
rails (~> 5.1.5.rc1)

browser-timezone-rails was resolved to 1.1.0, which depends on
  rails (>= 3.1)

Bundler could not find compatible versions for gem "redis":
In Gemfile:
redis (< 4)

capistrano-resque (~> 0.2.2) was resolved to 0.2.3, which depends on
  resque-scheduler was resolved to 4.4.0, which depends on
    redis (>= 3.3)

sidekiq-scheduler was resolved to 3.0.1, which depends on
  redis (>= 3, < 5)

Bundler could not find compatible versions for gem "ruby":
In Gemfile:
ruby (~> 2.4.4.0)

acts_as_list was resolved to 1.0.1, which depends on
  ruby (>= 2.4.7)

Bundler could not find compatible versions for gem "web-console":
In Gemfile:
web-console (>= 3.3.0)

Help me to solve this issue

When the initial connection is to an invalid tenant (non-existant db,
for example), the app process can never successfully reconnect to a
valid tenant.
Ludicrous amount of rescues.
If it does, we lose the consistency of @current, which seems to be
what's happening.
When the process is forked or a new thread is started, set-up our
ActiveRecord connection_specification_name overrides again because
programs like Passenger will now call
`ActiveRecord::Base.establish_connection` when they spawn new app
processes, which in turn cause
`ActiveRecord::Base.connection_specification_name` to be reset to
whatever is specified in database.yml (or :primary as default).

I can't see that this could have any adverse affects. If the app sets
`connection_specification_name` on anything other than
`Apartment.connection_class` (`ActiveRecord::Base` by default) that
should be unaffected and preserved.

This is a more generic solution that hooking into some
Passenger-specific after-spawn hook.
@hamza-costiq
Copy link

When the threading issue with Puma will be resolved in Apartment Gem ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants