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.
Setup
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 create the connection on startup. That leaves you with one connection and one channel. The downside is you have to manage the connection and ensure it is always up and running.
The method I describe below is a hybrid of the two. I lazy load the connection and channel. The first time we publish a message, we will setup the connection and leave it open. If we publish again then we 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.
Connection Manager
Create our ConnectionManager
singleton class.
class ConnectionManager
include Singleton
def initialize
establish_connection
end
end
Establish Connection
We 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
A connection might close overtime. Let’s check its health each time we access the channel
or connection
.
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
Publisher
Add our publisher.
class Publisher
DEFAULT_OPTIONS = { durable: true, auto_delete: false }.freeze
def self.publish(queue_name:, payload:)
channel = ConnectionManager.instance.channel
queue = channel.queue(queue_name, DEFAULT_OPTIONS)
queue.publish(payload, routing_key: queue.name)
end
end
Now we can publish.
Publisher.publish(queue_name: "greetings", payload: { hello: :world })
Useful Resources
Did you like this article? Check out these too.
Found this useful? Have a suggestion? Get in touch at blog@hocnest.com
.