I like a lot RabbitMQ . It is a really good system when you have to work with events and build your systems with asynchrony in mind. Although silver bullets do not exist in the SW world, when you require a complex routing, scalability and reliability, RabbitMQ is your system.

I usually work in a polyglot environment, but when one of the systems has to deal with a lot of connections (i.e. Message Queue Systems, Databases, Web Servers, ...) Elixir is my choice. And when I have to deal with RabbitMQ I use a wonderful library, pma/amqp .

When we code several projects that involve the same language and the interaction with the same system, we always have to build the same code base. In this case, a connection to RabbitMQ and the different channels with their own callbacks. The only difference between the code which manages the channels are the callabacks; therefore I decided to create a OTP application which will always take care of this common code, the name -> Conejo (Rabbit in Spanish).
I began creating a module which will take care of the RabbitMQ connection (only one tcp connection per project, if you have more "connections" use the channels). This module will be a GenServer which will be supervise by a Supervisor .

Once that I had the connection, I decide to create some Behaviours which will decrease the complexity of working with RabbitMQ: Conejo.Consumer and Conejo.Publisher. Both of them are based on GenServer. If you want to use the first one, you will only implement a function consume ( channel , tag , redelivered , payload ) and if you use the second one, you don't need to implement any code on your module to make it work.

defmodule MyApplication.MyConsumer do
use Conejo.Consumer

def consume(_channel, _tag, _redelivered, payload) do
end
end

options = Application.get_all_env(:my_application)[:consumer]

{:ok, consumer} = MyApplication.MyConsumer.start_link(options, [name: :consumer])

defmodule MyApplication.MyPublisher do
use Conejo.Publisher

end

{:ok, publisher} = MyApplication.MyPublisher.start_link([], [name: :publisher])

#Synchronous
MyApplication.MyPublisher.sync_publish(:publisher, "my_exchange", "example", "Hola")

#Asynchronous

Previously, you have to define the configurations for the conejo connection (mandatory) and your channels (if you want). Conejo respects the configuration of pma/amqp. For example:

config :my_application, :consumer,
exchange: "my_exchange",
exchange_type: "topic",
queue_name: "my_queue",
queue_declaration_options: [{:auto_delete, true}, {:exclusive, true}],
queue_bind_options: [routing_key: "example"],
consume_options: [no_ack: true]

config :conejo,
host: "my_host",
port: 5672,

As you can see, really easy.

# mix.exs