Enabling multi-tenancy with werkzeug

Wednesday, 01 December, 10:00AM – 10:25AM (UTC)

Learn how to convert your existing application into a multi-tenant application within a day. This is a case study on how our simple flask web-application was changed to a multi-tenant architecture and simplified our client onboarding experience and reduced our infrastructure burden.

This talk is a case study about how the web-application I am building at work (in Corridor Platforms) started as a simple web application. But over time, we wanted to enable some cool features like: - Enable a “try” capability for users to try the application out before buying - Create an isolated sandbox environments for users - Enabling training environments for new user onboarding - Creating a SaaS offering for multiple users And so on. We were initially handling this at an infrastructure level, but using separate processes/databases/etc. For each “isolated instance” we needed to create. But it was obvious that this had a lot of gaps: - Creating and maintaining multiple instances was a technology nightmare for administrators - Managing configuration consistency across instances was difficult - Every instance needs a certain set of minimum requirements (CPU, RAM, etc.) We decided to venture into the foray of multi-tenant applications, and there are a lot of resources available on how this could work. But handling this along with other dependencies celery, database, upload-management, etc. was not easy. So, we went with a middle ground approach of how we can toggle between multiple flask applications using werkzeug’s DispatcherMiddleware and LocalProxy - which enabled us to create a working multi-tenant application within a few hours! We will go into 2 methods that we attempted to do: **Approach #1**: Creating multiple separate flask applications for each tenant Using DispatcherMiddleware, we can create a proxy (similar to nginx reverse-proxy) for each tenant, and let the flask application for each tenant manage what it needs to do. This can be done using URL prefixes - similar to how google applications like gmail handle it. **Approach #2**: Using a single flask application for all the tenants, but different configs, connections, etc. Here, we create a separate LocalProxy (similar to how current_app, request, g, etc.use it) - to switch based on the tenant that is currently being used. This approach is a bit more delicate as multiple aspects need to be handled. Each of the tenant-related resource needs to be handled individually: Database connections, settings, cache connections, celery brokers, LDAP connections, etc. - and many more depending on what your web application uses. While this is more optimal, it is also more effort to implement. Along with these, we can also enable multi-tenancy at a database level with some sqlalchemy magic. Sqlalchemy’s Query class and compiler hooks allow us to mimic a database multi-tenancy without actually having multiple table schemas. Which again, reduces the effort of handling multiple database schema and migration efforts. By the end of the talk, the participants will have some good insight into the internals of werkzeug and sqlalchemy - and also see a visible use case of how an application can be converted into a multi-tenant application with minimal effort.

Abdeali (Ali) Kothari

FlaskCon Speaker