Skip to content

Add support for AbstractRoutingConnectionFactory #98

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

Closed
zahidraza opened this issue Apr 22, 2019 · 4 comments
Closed

Add support for AbstractRoutingConnectionFactory #98

zahidraza opened this issue Apr 22, 2019 · 4 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@zahidraza
Copy link

In non-reactive spring application, ORM tool like Hibernate provides a way to resolve tenant and thereby make the call to appropriate database or schema. Multi-Tenancy is achieved by implementing MultiTenantConnectionProvider and CurrentTenantIdentifierResolver interfaces.

Is there a way to implement multi-tenancy using r2dbc. Is it supported as of now?
If no, what is the roadmap going forward for this feature?

@mp911de
Copy link
Member

mp911de commented Apr 23, 2019

CurrentTenantIdentifierResolver is a resource-factory-level callback that returns a tenant-id from a parameter-less method. Typically, implementations use ThreadLocal storage to configure routing.

In Reactive Streams, we no longer can use ThreadLocal to pass items between involved components. Project Reactor introduced a custom abstract, the Subscriber Context that can be used to attach contextual values to a subscription.

Based on Context, we could provide an AbstractRoutingConnectionFactory that does the exact same as AbstractRoutingDataSource by fetching a lookup value from Context to give you the appropriate tenant-specific connection.

Do you want to have a look at AbstractRoutingDataSource and come up with a pull request?

Connection routing isn't currently on our roadmap. If we receive a pull request, then we can include that feature.

@mp911de mp911de added the type: enhancement A general enhancement label Apr 23, 2019
@mp911de mp911de changed the title Multi-Tenancy using r2dbc Add support for AbstractRoutingConnectionFactory Apr 23, 2019
@mp911de mp911de added the status: ideal-for-contribution An issue that a contributor can help us with label Apr 23, 2019
@simontb
Copy link

simontb commented May 3, 2019

I think when used in conjuction with r2dbc-pool, a tenant-specific connection might not be the ideal solution depending on the implementation of tenant separation. This would make most sense when each tenant resides on his own database. When tenants are identified by schema or column, the same db connection could be used for multiple tenants.

@mp911de
Copy link
Member

mp911de commented May 3, 2019

There's a vast amount of design patterns for multi-tenancy, connection/database/schema per tenant is one of them. From a consistency point of view, it makes a lot of sense to provide a routing ConnectionFactory.

@mp911de mp911de self-assigned this May 28, 2019
mp911de added a commit that referenced this issue May 28, 2019
mp911de added a commit that referenced this issue May 28, 2019
We now provide an abstract base class for ConnectionFactory routing. Routing keys are typically obtained from a subscriber context. AbstractRoutingConnectionFactory is backed by either a map of string identifiers or connection factories. When using string identifiers, these can map agains e.g. Spring bean names that can be resolved using BeanFactoryConnectionFactoryLookup.

class MyRoutingConnectionFactory extends AbstractRoutingConnectionFactory {

		@OverRide
		protected Mono<Object> determineCurrentLookupKey() {
			return Mono.subscriberContext().filter(it -> it.hasKey(ROUTING_KEY)).map(it -> it.get(ROUTING_KEY));
		}
}

@bean
public void routingConnectionFactory() {

		MyRoutingConnectionFactory router = new MyRoutingConnectionFactory();

		Map<String, ConnectionFactory> factories = new HashMap<>();
		ConnectionFactory myDefault = …;
		ConnectionFactory primary = …;
		ConnectionFactory secondary = …;

		factories.put("primary", primary);
		factories.put("secondary", secondary);

		router.setTargetConnectionFactories(factories);
		router.setDefaultTargetConnectionFactory(myDefault);

		return router;
}
@mp911de mp911de removed the status: ideal-for-contribution An issue that a contributor can help us with label May 28, 2019
@mp911de mp911de added this to the 1.0 M3 milestone May 28, 2019
@mp911de mp911de assigned schauder and unassigned mp911de May 28, 2019
schauder added a commit that referenced this issue Jun 4, 2019
Formatting.
Changed generics to avoid unchecked casting.
Avoided abbreviated variable name.
Simplified handling of absent keys at ConnectionFactory lookup.
schauder pushed a commit that referenced this issue Jun 4, 2019
We now provide an abstract base class for ConnectionFactory routing. Routing keys are typically obtained from a subscriber context. AbstractRoutingConnectionFactory is backed by either a map of string identifiers or connection factories. When using string identifiers, these can map agains e.g. Spring bean names that can be resolved using BeanFactoryConnectionFactoryLookup.

class MyRoutingConnectionFactory extends AbstractRoutingConnectionFactory {

		@OverRide
		protected Mono<Object> determineCurrentLookupKey() {
			return Mono.subscriberContext().filter(it -> it.hasKey(ROUTING_KEY)).map(it -> it.get(ROUTING_KEY));
		}
}

@bean
public void routingConnectionFactory() {

		MyRoutingConnectionFactory router = new MyRoutingConnectionFactory();

		Map<String, ConnectionFactory> factories = new HashMap<>();
		ConnectionFactory myDefault = …;
		ConnectionFactory primary = …;
		ConnectionFactory secondary = …;

		factories.put("primary", primary);
		factories.put("secondary", secondary);

		router.setTargetConnectionFactories(factories);
		router.setDefaultTargetConnectionFactory(myDefault);

		return router;
}

Original pull request: #132.
schauder added a commit that referenced this issue Jun 4, 2019
Formatting.
Changed generics to avoid unchecked casting.
Avoided abbreviated variable name.
Simplified handling of absent keys at ConnectionFactory lookup.

Original pull request: #132.
@schauder
Copy link
Contributor

schauder commented Jun 4, 2019

This is resolved by e3aae61

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

No branches or pull requests

4 participants