Smex

An Elixir library for simplifying the sending of protocol buffers over rabbitmq. This is intended to allow compatible communication with the more comprehensive ruby framework Smith but this can be used on it's own as a way of using protocol buffers and rabbitmq.

Usage

Add Dependendencies & Application

Add this library to your dependendencies like {:smex, github: "DylanGriffith/smex"}. Then add :smex to your applications.

Configure The Location Of Your Protocol Buffers

You will also need your own protocol buffers in some directory then configure that in config/config.exs like:

config :smex,
  protobuf_dir: "/path/to/my/protobufs"

This directory can contain any .proto files and they will automatically be compiled. For the purposes of the following examples you can just have a single file call in the directory called greeting.proto containing:

package PB;

message Greeting {
  required string greeting = 1;
}

All protocol buffers are compiled to structs.

NOTE: I have to use a forked version of the exprotobuf to support the features I needed so you may have problems if you already have exprotobuf as a dependency. I will fix this when the proper one has the features I need which seems to at least be in progress.

Sending Messages

Now your ready to start sending messages:

{:ok, connection} = Smex.connect("amqp://guest:guest@localhost")

{:ok, channel} = Smex.open(connection)

message = PB.Greeting.new(greeting: "Hello, World!")
queue = "smex.test.some_test_queue"

:ok = Smex.publish(channel, message, destination: queue)

Subscribing In A GenServer

Then if you want to subscribe to messages you can create a simple GenServer like:

defmodule MyServer do
  use GenServer
  use Smex.Agent

  def init(_opts) do
    # Setup the connection
    {:ok, connection} = Smex.connect("amqp://guest:guest@localhost")
    {:ok, channel} = Smex.open(connection)

    # Subscribe to desired queue
    consumer_tag = Smex.subscribe(channel, queue_name: "smex.test.some_test_queue")

    # Standard GenServer return
    {:ok, %{connection: connection, channel: channel, consumer_tag: consumer_tag}}
  end

  # Pattern match just the protocol buffer types you expect on this queue
  def handle_cast({:smex_message, m = %PB.Greeting{}, meta}, state = %{channel: chan}) do
    IO.puts("Received a PB.Greeting:")
    IO.inspect(m)

    # Acknowledge receipt of message. This is necessary.
    Smex.ack(chan, meta)

    # Standard GenServer return
    {:stop, :normal, state}
  end
end

Since this is just a standard GenServer you can add to any supervision tree you want or do any other stuff you can do with a GenServer.

Motivation

RabbitMQ is awesome and asynchronous message passing is so hot right now. AMQP is complicated with lots of features that it forces you to understand even for simple use cases. Protocol buffers are fast and efficient data formats and translate neatly into elixir structs. This library provides a really straightforward way of getting started with these awesome libraries and intends to still provide you with the option of utilising more advanced features of AMQP when/if you eventually need it.