Home

Awesome

kanin

<a href="http://aquarius-galuxy.deviantart.com/art/Rabbit-Drawing-176749973"><img src="resources/images/kanin-small.png" /></a>

An LFE Wrapper for the Erlang RabbitMQ (AMQP) Client

Table of Contents

Introduction

The kanin library is a wrapper for various modules in the Erlang AMQP client library. kanin was created in order to not only provide a less verbose AMQP client library for LFE hackers, but one that was also more Lispy.

Dependencies

As of version 0.3.0 of kanin, the latest version of lfetool is required (currently lfetool 1.5.0-dev). This is due to the fact that kanin has started using the lfe.config file to override rebar dependencies. kanin uses the latest development release of LFE in order to support including various RabbitMQ Erlang header files, and since other dependencies use the latest release of LFE (0.9.0), we needed to override rebar's behaviour (see the rebar bug #170).

To install the latest development version of lfetool:

$ curl -L -o ./lfetool https://raw.github.com/lfe/lfetool/dev-v1/lfetool
$ bash ./lfetool install

Installation

To pull in kanin as part of your project, just add it to your rebar.config deps:

  {deps, [
    ...
    {kanin, ".*",
      {git, "git@github.com:billosys/kanin.git", "master"}}
      ]}.

And then do:

    $ make compile

This will take a little while, as it builds the Erlang RabbitMQ client library from source. If you have amqp_lib on your $ERL_LIBS path, then you can do this instead:

    $ make skip-rabbit

Documentation

Below, in the "Usage" section, you will find information about using Kanin with RabbitMQ in LFE projects.

Also, you may be interested in the Kanin tutorials, which have been translated into LFE from the official RabbitMQ docs for Python and Erlang.

Supported Modules

The following amqp_* modules have been included in kanin:

If your favorite amqp_* module is not among those, feel free to submit a new ticket requesting the addition of your desired module(s) or submit a pull request with the desired inclusion added.

Usage

Copyright Notice

The following content was copied from the Erlang Client User Guide on the RabbitMQ site. The original copyright was in 2014, held by Pivotal Software, Inc.

The LFE AMQP Client Library

The AMQP client provides an Erlang interface to compliant AMQP brokers. The client follows the AMQP execution model and implements the wire level marshaling required to encode and decode AMQP commands in a protocol conformant fashion. AMQP is a connection orientated protocol and multiplexes parallel interactions via multiple channels within a connection.

This user guide assumes that the reader is familiar with basic concepts of AMQP and understands exchanges, queues and bindings. This information is contained in the protocol documentation on the AMQP website. For details and exact definitions, please see the AMQP specification document.

The basic usage of the client follows these broad steps:

Programming Model

Once a connection has been established, and a channel has been opened, an LFE application will typically use the kanin-chan:call/{2,3} and kanin-chan:cast/{2,3} functions to achieve most of the things it needs to do.

The underlying Erlang AMQP client library is made up of two layers:

There are two drivers in the client library:

At run-time, the Erlang client library re-uses a subset of the functionality from the RabbitMQ broker. In order to keep the a client deployment independent of RabbitMQ, the Erlang client build process produces an archive containing all of the common modules. This archive is then put onto the load path of the client application.

For more detailed information on the API, please refer to the reference documentation.

Furthermore, the test suite that is part of the source distribution of the client library contains many complete examples of how to program against the API.

AMQP Commands

The general mechanism of interacting with the broker is to send and receive AMQP commands that are defined in the protocol documentation. During build process, the machine-readable version of the AMQP specification is used to auto-generate Erlang records for each command. The code generation process also defines sensible default values for each command. Using default values allows the programmer to write terser code - it is only necessary to override a field if you require non-default behaviour. The definition of each command can be consulted in the include/rabbit-framing.lfe header file. For example, when using the (make-exchange.declare ...) record-creating macro, specifying the following:

(make-exchange.declare exchange (list_to_binary "my_exchange"))

is equivalent to this:

(make-exchange.declare
  exchange (list_to_binary "my_exchange")
  ticket 0
  type (list_to_binary "direct")
  passive 'false
  durable 'false
  auto_delete 'false
  internal 'false
  nowait 'false
  arguments '())

Including Header Files

The LFE client uses a number of record definitions which you will encounter in this guide. These records fall into two broad categories:

To gain access to these records, you need to include the amqp-client.lfe file in every module that uses the Erlang client:

(include-lib "kanin/include/amqp-client.lfe")

Connecting to a Broker

The kanin-conn module is used to start a connection to the broker:

...
  (let* ((net-opts (make-amqp_params_network host "localhost"))
         (`#(ok ,connection) (kanin-conn:start net-opts))
         ...))
...

This function returns #(ok ,connection), where connection is the pid of a process that maintains a permanent connection to the broker.

In case of an error, the above call returns #(error ,error).

The example above has just "localhost" as a parameter. However, there will often be many more than that.

An AMQP broker contains objects organised into groups called virtual hosts. The concept of virtual hosts gives an administrator the facility to partition a broker resource into separate domains and restrict access to the objects contained within these groups. AMQP connections require client authentication and the authorisation to access specific virtual hosts.

The (make-amqp_params_network) record macro sets the following default values:

ParameterDefault Value
usernameguest
passwordguest
virtual_host/
hostlocalhost
post5672
channel_max0
frame_max0
heartbeat0
ssl_optionsnone
auth_mechanisms(list #'amqp_auth_mechanisms:plain/3 #'amqp_auth_mechanisms:amqplain/3)
client_properties'()

These values are only the defaults that will work with an out of the box broker running on the same host. If the broker or the environment has been configured differently, these values can be overridden to match the actual deployment scenario.

SSL options can also be specified globally using the ssl_options environment key for the amqp-client application. They will be merged with the SSL parameters from the URI (the latter will take precedence).

If a client wishes to run inside the same Erlang cluster as the RabbitMQ broker, it can start a direct connection that optimises away the AMQP codec. To start a direct connection, use kanin-conn:start/1 with the parameter set to an (make-amqp_params_direct) record.

Providing a username and password is optional, since the direct client is considered trusted anyway. If a username and password are provided then they will be checked and made available to authentication backends. If a username is supplied, but no password, then the user is considered trusted and logged in unconditionally. If neither username nor password are provided then the connection will be considered to be from a "dummy" user which can connect to any virtual host and issue any AMQP command.

The (make-amqp_params_direct) record macro sets the following default values:

ParameterDefault Value
usernameguest
passwordguest
virtual_host/
node(node)
client_properties'()

Connecting To A Broker with AMQP URIs

Instead of working the (make-amqp_params_*) records directly, AMQP URIs may be used. The (kanin-uri:parse/1) function is provided for this purpose. It parses an URI and returns the equivalent amqp_params_* record. Diverging from the spec, if the hostname is omitted, the connection is assumed to be direct and an amqp_params_direct record is returned. In addition to the standard host, port, user, password and vhost parameters, extra parameters may be specified via the query string (e.g. "?heartbeat=5").

AMQP URIs are defined with the following ABNF rules:

amqp_URI       = "amqp://" amqp_authority [ "/" vhost ] [ "?" query ]
amqp_authority = [ amqp_userinfo "@" ] host [ ":" port ]
amqp_userinfo  = username [ ":" password ]
username       = *( unreserved / pct-encoded / sub-delims )
password       = *( unreserved / pct-encoded / sub-delims )
vhost          = segment

Here are some examples:

ParameterUsernamePasswordHostPortVhost
amqp://alice:secret@host:10000/vhost"alice""secret""host"10000"vhost"
amqp://bo%62:%73ecret@h%6fst:10000/%76host"bob""secret""host"10000"vhost"
amqp://
amqp://:@/""""""
amqp://carol@"carol"
amqp://dave:secret@"dave""secret"
amqp://host"host"
amqp://:1000010000
amqp:///vhost"vhost"
amqp://host/"host"""
amqp://host/%2f"host""/"
amqp://[::1]"[::1]"

If you prefer, you can use connection URIs in Kanin. Updating the previous example:

...
  (let* ((net-opts (kanin-uri:parse "amqp://localhost"))
         (`#(ok ,connection) (kanin-conn:start net-opts))
         ...))

Creating Channels

TBD

Managing Exchanges and Queues

TBD

Sending Messages

TBD

Receiving Messages

TBD

Subscribing to Queues

TBD

Subscribing Internals

TBD

Closing Channels and the Connection

TBD

Complete Example

TBD

Client Deployment

TBD

Egress Flow Control

TBD

Ingress Flow Control

TBD

Handling Returned Messages

TBD