Skip to content

mgmeiner/spring-mongodb-multi-tenancy-example

Repository files navigation

spring-mongodb-multi-tenancy-example

Example project which demonstrates multi-tenancy support with reactive mongo and spring

This project is just a proof of concept if and how it works.

Example problem to be solved

We assume we need a service which provides a simple api for products. This service can be configured for multiple customers which product data is stored in different databases for security reasons.

How it works

The tenants can configured via standard spring ConfigurationProperties (TenantProperties).

To distinguish between the customer I simply added a WebFilter (TenantExtractingWebFilter) which extracts the tenantId from a http header (X-Tenant). In reality you would get that tenantId from a jwt token for example.

The filter puts the tenantId in the Project Reactor's Context to provide it for upstream reactor flow.
This tenantId can now be accessed in any upstream calls initiated through a http request.

Now the tricky part:

ReactiveMongoTemplate simply does not support multi-tenancy. It gets only one ReactiveMongoDatabaseFactory for one MongoClient and thus cannot 'route' the queries to different databases.

I implemented a MultiTenancyReactiveMongoTemplate which takes a MultiTenancyReactiveMongoDatabaseFactory which simply extends SimpleReactiveMongoDatabaseFactory with the tenantId. Internally the MultiTenancyReactiveMongoTemplate creates a ReactiveMongoTemplate for each MultiTenancyReactiveMongoDatabaseFactory and holds them. On each call on any public api of MultiTenancyReactiveMongoTemplate it internally delegates to the respective ReactiveMongoTemplate by retrieving the tenantId from the subscriberContext.

The auto-configuration for this is done by MultiTenancyConfiguration which creates it from the provided TenantProperites.

This works for almost all classic interactions of MongoOperations including auto-index creation and usage of ReactiveMongoRepository. Look at the Problems sections for operations which do not work and other limitations.

Problems and limitations

A few operations as

  • changeStream (ReactiveChangeStream)
  • indexOps (except the automatic index creation during startup)
  • inTransaction
  • withSession

do not work with this implementation as they would need new delegating implementations or are currently simply not possible as they return scalar values and so there is no possibility to access the subscriberContext.

Run Demo

  • clone repo
  • run docker-compose up -d to spin up a local mongodb instance for simple testing
  • run mvnw spring-boot:run to start the app
  • use the 'insomnia_workspace.json' and import the workspace into Insomnia

About

Example project which demonstrates multi-tenancy support with reactive mongo and spring

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages