rails amqp bunny rabbitmq

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 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

Our ConnectionManager singleton will establish a connection on initialize.

class ConnectionManager
  include Singleton

  def initialize
    establish_connection
  end
end

Establish Connection

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

Publishing

We can access the channel or connection from the ConnectionManager instance:

channel = ConnectionManager.instance.channel
connection = ConnectionManager.instance.connection

Useful Resources

 

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 blog@hocnest.com