Tuesday, March 22, 2016

Supporting Multi-tenancy with Spring AMQP

In this post I'm going to discuss how you can publish messages to RabbitMQ via Spring AMQP to different vhosts with a single ConnectionFactory.

Lets say you have the need for a single application to send messages to multiple vhosts. You might use this method to support securely sending messages to multiple clients, each one with a different username/password. With Spring AMQP the way in which you connect to a vhost is by creating a ConnectionFactory which is an interface with the main implementation being a CachingConnectionFactory. The problem is that this will only allow you to connect to a single vhost. Luckily ConnectionFactory is just an interface and as of spring-amqp 1.3 there is now an implementation that allows you to "route" to other connection factories via an abstract class called AbstractRoutingConnectionFactory which uses a Map of connection factories. One implementation is SimpleRoutingConnectionFactory which uses a thread bound context to determine the key to the Map.

So we need an Event class to encapsulate our message, and a Service for sending it. Let's do that here:

As you can see from the above code we have created our event interface and an implementation and also a service with an implementation. The service is responsible for binding and unbinding the thread bound context to the clientId for proper routing of the message. The rest is just standard spring-amqp code to send the message via the RabbitTemplate.convertAndSend method. The next missing link is the Spring configuration to glue all of this stuff together. Let's do that next!

In the above code we have a Spring configuration that wires up the MyEventService with a RabbitTemplate that is configured with our SimpleRoutingConnectionFactory. Please note that I have not included any auto configuration of Queues or Transaction management here because that's outside the scope of what I'm trying to cover here. Finally all we have to do is obtain a MyEventService from the Spring ApplicationContext and send a message.

In the above program we obtain the MyEventService from the ApplicationContext and send an event that gets routed to each client. All the magic is in the SimpleRoutingConnectionFactory.

Possible Improvements
One limitation to this solution is that you have to know the vhost connection information at the time the application is started. So if you get a new client, you will have to at worst make a code change and at least bounce the server. The way I have overcome this is by extending the SimpleRoutingConnectionFactory and creating an implementation that creates connection factories at run time based on a Clients database table. I will create another post in the future about how to do this.

Summary
In this post we created a generic MyEvent class that holds information about the event message and how to route it.We also created a MyEventService that handles sending that event to the configured RabbitTemplate. We also configured our RabbitTemplate to support multiple vhosts to support a multi tenant architecture. I hope this gives you an idea about how to implement such a solution in your applications.

Please feel free to leave questions or comments below. Thanks for reading!

1 comment:

  1. please can we also get a blog for rabbitListener in case of multitenancy !

    ReplyDelete

Note: Only a member of this blog may post a comment.