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 IO.puts "Received -> #{inspect payload}" 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 MyApplication.MyPublisher.async_publish(:publisher, "my_exchange", "example", "Adios")
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, username: "user", password: "pass"
As you can see, really easy.
Add to your project and begin to use it :D
# mix.exs def deps do [{:conejo, git: "https://github.com/mendrugory/conejo.git"}] # or [{:conejo, "~> 0.1.0"}] when is available end def application do [applications: [:conejo]] end
Check it in
Github
.