, ,

Rebar is a great tool for managing builds and dependencies in Erlang. I wanted to write a AMQP client using the RabbitMQ client example and use rebar for the build management. Getting the two to play nice wasn’t so bad, but there were a few devils to work out.

The first step is to get rebar and add it to your path. Note that rebar only works with recent versions of Erlang/OTP and also requires SSL. On Mac OS X this can be done with MacPorts using a special command (port -v upgrade –enforce-variants erlang +ssl). Others have suggested using HomeBrew to install Erlang and RabbitMQ. Having just migrated to MacPorts from fink, I didn’t feel like migrating to another package management system twice in one day.

Create Application Stub

Once rebar is installed, create an application stub using the standard approach.

$ mkdir my_amqp
$ cd my_amqp
$ rebar create-app appid=my_amqp

The default template will create the application stubs including a supervisor. None of this is really needed for running the RabbitMQ example, but it can be saved for later for writing an actual application.

Configure Project

A useful feature of rebar is the dependency management. In a nutshell, rebar will recursively download all declared dependencies from source and compile them as well. This is pretty cool, although it would be great to have tagged binaries similar to Maven repositories. The documentation doesn’t mention how to configure the dependency management, but if you peruse the sample configuration, it provides some details. I cheated and used the config for gen_bunny, written by the same people as rebar.

Your rebar.config should contain the following.

{deps, [
 {amqp_client, ".*",
 {git, "git://github.com/dreid/amqp_client.git", "master"}},
 {rabbit_common, ".*",
 {git, "git://github.com/dreid/rabbit_common.git", "master"}}

You can optionally add a Makefile as well, since that is the pattern used in gen_bunny. I’ll assume that the authors know what they are doing 😉 and follow the process.


.PHONY: all erl test clean doc

all: erl

 $(REBAR) get-deps compile

test: all
 @mkdir -p .eunit
 $(REBAR) skip_deps=true eunit

 $(REBAR) clean
 -rm -rvf deps ebin doc .eunit

 $(REBAR) doc

Note that as with any Makefile, the lines in each section must be indented with a tab.

Test Client

Attempting to run the example provided on the RabbitMQ web site didn’t work for me. Upon further inspection, it appeared that the API has changed a bit but the example was neglected. Here is updated code that will run properly. Note that this assumes that your RabbitMQ process is running in a separate process. Otherwise, replace the atom network with direct.


test() ->
  {ok, Connection} = amqp_connection:start({network, #amqp_params{}}),
{ok, Channel} = amqp_connection:open_channel(Connection),
#'queue.declare_ok'{queue = Q}
    = amqp_channel:call(Channel, #'queue.declare'{}),
Payload = <<"foobar">>,
  Publish = #'basic.publish'{exchange = <<>>, routing_key = Q},
  amqp_channel:cast(Channel, Publish, #amqp_msg{payload = Payload}),
Get = #'basic.get'{queue = Q},
  {#'basic.get_ok'{delivery_tag = Tag}, Content}
= amqp_channel:call(Channel, Get),
  % Do something with the message payload.......and then ack it
amqp_channel:cast(Channel, #'basic.ack'{delivery_tag = Tag}),

Running the Example

Once everything is built, just make sure your RabbitMQ server is already started. For this example, the default authentication credentials are being used. Obviously if you change these, you’ll need to update the example.

$ make
$ ERL_LIBS=deps erl -pa ebin

> amqp_example:test().

=INFO REPORT==== 24-Jan-2011::11:39:34 ===
Negotiated maximums: (Channel = 0, Frame = 131072, Heartbeat = 0)