influitive / apartment

Database multi-tenancy for Rack (and Rails) applications
2.66k stars 464 forks source link

Active maintained? #636

Open h0jeZvgoxFepBQ2C opened 4 years ago

h0jeZvgoxFepBQ2C commented 4 years ago

Hi & thanks for this wonderful gem.

Right now I'm (and others as it seems , see #632 ) are not sure if this gem is still actively maintained? Or are you looking maybe for further maintainers?

Pinging @bradrobertson @meganemura (as you have been the most active committers as far as I saw it).

Thank you for your reply!

lcjury commented 4 years ago

@mikecmpbll is the current maintainer of this repository. I haven't see activity from him in the last 6 months, and there was very little activity on the last year.

But, as you have seen in https://github.com/influitive/apartment/pull/624, @rpbaltazar made a fork on https://github.com/rails-on-services/apartment to keep improving the gem.

h0jeZvgoxFepBQ2C commented 4 years ago

Ah I see.. @mikecmpbll would be great if you could tell us how you would like to continue too?

etewiah commented 4 years ago

There is an actively maintained fork here: https://github.com/rails-on-services/apartment

Also came across this gem which works well for postgres: https://github.com/ramontayag/storey

styrmis commented 4 years ago

In case it is helpful to anyone, I can confirm that it is feasible to safely remove apartment from an app (at least when using Postgres) by:

  1. Converting all models to use UUIDs instead of autoincrement ids
  2. Associate all models to be scoped with a model such as Account
  3. Implement a more typical multitenant setup within the current apartment-based setup (so you are essentially scoping to the tenant twice). This would involve e.g. converting all queries from being like Client.all to current_account.clients.all, and so on.
  4. Finally, remove apartment

Following this approach took quite a lot of time but it did allow for smooth removal of the gem.

I will say that the gem was very useful in getting started with that particular app so I appreciate the work that has gone into it over the years. I would however for the vast majority of cases stick with a more typical multitenant setup for any future apps, unless they had strict requirements for tenant data to be hosted in separate database instances.

kitsunde commented 4 years ago
  1. Converting all models to use UUIDs instead of autoincrement ids

Is this because you're merging schemas together and need to migrate all keys?

  1. Associate all models to be scoped with a model such as Account
  2. Implement a more typical multitenant setup within the current apartment-based setup (so you are essentially scoping to the tenant twice). This would involve e.g. converting all queries from being like Client.all to current_account.clients.all, and so on.

What does scoping to the tenant twice mean? It sounds like you've implemented column-based tenancy. So say each tenant has a Tenant, then each model would end up with a tenant_id right? It's certainly one way of achieving multi-tenancy but there are also drawbacks to this where every DB query would end up doing that resolution, both in business logic requiring this scoping constantly and in db performance.

styrmis commented 4 years ago
  1. Converting all models to use UUIDs instead of autoincrement ids

Is this because you're merging schemas together and need to migrate all keys?

Yes, the data from all schemas were copied into the public schema as part of the final deployment to remove the gem.

  1. Associate all models to be scoped with a model such as Account
  2. Implement a more typical multitenant setup within the current apartment-based setup (so you are essentially scoping to the tenant twice). This would involve e.g. converting all queries from being like Client.all to current_account.clients.all, and so on.

What does scoping to the tenant twice mean? It sounds like you've implemented column-based tenancy. So say each tenant has a Tenant, then each model would end up with a tenant_id right? It's certainly one way of achieving multi-tenancy but there are also drawbacks to this where every DB query would end up doing that resolution, both in business logic requiring this scoping constantly and in db performance.

Scoping twice means that Apartment is scoping by schema, and within that the application scopes to a Tenant model, in my case Account. The scoping via Account is redundant at that point, as Apartment has already limited all queries to the data in the schema of that particular tenant.

Once Apartment is removed then the queries continue to return only those records associated with the given tenant. This approach allowed for the replacement multitenant scoping to be implemented over time while leaving Apartment in place.

There are certainly potential drawbacks to this (and any other) solution, so I would not recommend it in all cases, but for the scale of systems that I build this simple approach will suffice. I believe Basecamp operated for many years with this design, vertically scaling a single database instance, and certainly my applications are tiny compared to theirs.

When evaluating what to do about my app being blocked on a Rails 6 upgrade I was unsure if it would be feasible to remove Apartment in this manner. As such I have left these comments in case they are of use to someone else in a similar situation.

kitsunde commented 4 years ago

I see, thank you for clarifying. There are definitely issues with schema tenancy too at scale which I think is why apartment is no longer maintained here, some of them being fundamental to rails models which we are working at improving. If your application is small I think everything will be perfectly reasonable and up to whatever is the least trouble.

We've gone down the route of actively supporting an apartment fork (i.e. the one maintained by my colleague at https://github.com/rails-on-services/apartment) with Rails 6 which has also started porting in pending PR's and is under active development.