RabbitMQ and Rails
If you have a Rails application and want to start publishing messages to a RabbitMQ instance then you may be considering using Bunny. Getting started with the default configuration is very simple but fine tuning your setup for a production environment deserves more attention as each setting may greatly impact the eco system.
There are many different ways to implement a publisher in rails. I will highlight one method that I have used with success that utilizes a singleton class.
Many examples you will find online open and close a connection for each published message. This works well, especially for small scale applications and when the servers are in proximity of each-other. Although, for high volume message passing it is not an ideal solution. I don’t want to initiate a new connection with RabbitMQ, create a channel, send the message, and then close the connection every time I publish.
Another approach is to start a connection with an initializer. On startup, you create one connection and one channel. The obvious downside is you have to manage the connection and ensure it is always up and running.
The method I am describing below is somewhat of a hybrid of two. I lazy load my connection and channel. The first time we publish a message we will setup a connection and leave it open. If we publish again then we will use that connection. Prior to accessing the connection we check its status. For any reason the connection or channel is closed then we create a new one.
Setting up the Connection Manager
ConnectionManager singleton will establish a connection on initialize.
class ConnectionManager include Singleton def initialize establish_connection end end
Let’s establish the connection and create its channel.
attr_accessor :active_connection, :active_channel def establish_connection @active_connection = Bunny.new active_connection.start @active_channel = active_connection.create_channel @active_connection end
Accessing the Connection and Channel
There are many reasons a connection may close overtime. I like to check if the connection is open before attempting the publish to avoid waiting for a timeout.
def connection return active_connection if connected? establish_connection active_connection end def channel return active_channel if connected? && active_channel&.open? establish_connection active_channel end def connected? active_connection&.connected? end
We can access the channel or connection from the
channel = ConnectionManager.instance.channel connection = ConnectionManager.instance.connection
Did you like this article? Check out these too.
Found this useful? Know how it can be improved? Get in touch and share your thoughts at