amqp-0.9: Client library for AMQP servers (currently only RabbitMQ)

Safe HaskellNone

Network.AMQP

Contents

Description

A client library for AMQP servers implementing the 0-9-1 spec; currently only supports RabbitMQ (see http://www.rabbitmq.com)

A good introduction to RabbitMQ and AMQP 0-9-1 (in various languages): http://www.rabbitmq.com/getstarted.html, http://www.rabbitmq.com/tutorials/amqp-concepts.html

Example:

Connect to a server, declare a queue and an exchange and setup a callback for messages coming in on the queue. Then publish a single message to our new exchange

{-# LANGUAGE OverloadedStrings #-}
import Network.AMQP
import qualified Data.ByteString.Lazy.Char8 as BL

main = do
    conn <- openConnection "127.0.0.1" "/" "guest" "guest"
    chan <- openChannel conn

    -- declare a queue, exchange and binding
    declareQueue chan newQueue {queueName = "myQueue"}
    declareExchange chan newExchange {exchangeName = "myExchange", exchangeType = "direct"}
    bindQueue chan "myQueue" "myExchange" "myKey"

    -- subscribe to the queue
    consumeMsgs chan "myQueue" Ack myCallback

    -- publish a message to our new exchange
    publishMsg chan "myExchange" "myKey"
        newMsg {msgBody = (BL.pack "hello world"),
                msgDeliveryMode = Just Persistent}

    getLine -- wait for keypress
    closeConnection conn
    putStrLn "connection closed"


myCallback :: (Message,Envelope) -> IO ()
myCallback (msg, env) = do
    putStrLn $ "received message: " ++ (BL.unpack $ msgBody msg)
    -- acknowledge receiving the message
    ackEnv env

Exception handling:

Some function calls can make the AMQP server throw an AMQP exception, which has the side-effect of closing the connection or channel. The AMQP exceptions are raised as Haskell exceptions (see AMQPException). So upon receiving an AMQPException you may have to reopen the channel or connection.

Synopsis

Connection

data ConnectionOpts Source

Represents the parameters to connect to a broker or a cluster of brokers. See defaultConnectionOpts.

NOTICE: The field coMaxChannel was only added for future use, as the respective functionality is not yet implemented.

Constructors

ConnectionOpts 

Fields

coServers :: ![(String, PortNumber)]

A list of host-port pairs. Useful in a clustered setup to connect to the first available host.

coVHost :: !Text

The VHost to connect to.

coAuth :: ![SASLMechanism]

The SASLMechanisms to use for authenticating with the broker.

coMaxFrameSize :: !(Maybe Word32)

The maximum frame size to be used. If not specified, no limit is assumed.

coHeartbeatDelay :: !(Maybe Word16)

The delay in seconds, after which the client expects a heartbeat frame from the broker. If Nothing, the value suggested by the broker is used. Use Just 0 to disable the heartbeat mechnism.

coMaxChannel :: !(Maybe Word16)

The maximum number of channels the client will use.

coTLSSettings :: Maybe TLSSettings

Whether or not to connect to servers using TLS. See http:www.rabbitmq.com/ssl.html for details.

data TLSSettings Source

Represents the kind of TLS connection to establish.

Constructors

TLSTrusted

Require trusted certificates (Recommended).

TLSUntrusted

Allow untrusted certificates (Discouraged. Vulnerable to man-in-the-middle attacks)

defaultConnectionOpts :: ConnectionOptsSource

Constructs default connection options with the following settings :

  • Broker: amqp://guest:guest@localhost:5672/%2F using the PLAIN SASL mechanism
  • max frame size: 131072
  • use the heartbeat delay suggested by the broker
  • no limit on the number of used channels

openConnection :: String -> Text -> Text -> Text -> IO ConnectionSource

openConnection hostname virtualHost loginName loginPassword opens a connection to an AMQP server running on hostname. virtualHost is used as a namespace for AMQP resources (default is "/"), so different applications could use multiple virtual hosts on the same AMQP server.

You must call closeConnection before your program exits to ensure that all published messages are received by the server.

The loginName and loginPassword will be used to authenticate via the PLAIN SASL mechanism.

NOTE: If the login name, password or virtual host are invalid, this method will throw a ConnectionClosedException. The exception will not contain a reason why the connection was closed, so you'll have to find out yourself.

openConnection' :: String -> PortNumber -> Text -> Text -> Text -> IO ConnectionSource

same as openConnection but allows you to specify a non-default port-number as the 2nd parameter

openConnection'' :: ConnectionOpts -> IO ConnectionSource

Opens a connection to a broker specified by the given ConnectionOpts parameter.

closeChannel :: Channel -> IO ()Source

closes a channel. It is typically not necessary to manually call this as closing a connection will implicitly close all channels.

closeConnection :: Connection -> IO ()Source

closes a connection

Make sure to call this function before your program exits to ensure that all published messages are received by the server.

addConnectionClosedHandler :: Connection -> Bool -> IO () -> IO ()Source

addConnectionClosedHandler conn ifClosed handler adds a handler that will be called after the connection is closed (either by calling closeConnection or by an exception). If the ifClosed parameter is True and the connection is already closed, the handler will be called immediately. If ifClosed == False and the connection is already closed, the handler will never be called

Channel

data Channel Source

A connection to an AMQP server is made up of separate channels. It is recommended to use a separate channel for each thread in your application that talks to the AMQP server (but you don't have to as channels are thread-safe)

openChannel :: Connection -> IO ChannelSource

opens a new channel on the connection

addReturnListener :: Channel -> ((Message, PublishError) -> IO ()) -> IO ()Source

registers a callback function that is called whenever a message is returned from the broker ('basic.return').

qos :: Channel -> Word32 -> Word16 -> Bool -> IO ()Source

qos chan prefetchSize prefetchCount global limits the amount of data the server delivers before requiring acknowledgements. prefetchSize specifies the number of bytes and prefetchCount the number of messages. In both cases the value 0 means unlimited.

The meaning of the global flag is explained here: http://www.rabbitmq.com/consumer-prefetch.html

NOTE: RabbitMQ does not implement prefetchSize and will throw an exception if it doesn't equal 0.

Exchanges

data ExchangeOpts Source

A record that contains the fields needed when creating a new exhange using declareExchange. The default values apply when you use newExchange.

Constructors

ExchangeOpts 

Fields

exchangeName :: Text

(must be set); the name of the exchange

exchangeType :: Text

(must be set); the type of the exchange ("fanout", "direct", "topic", "headers")

exchangePassive :: Bool

(default False); If set, the server will not create the exchange. The client can use this to check whether an exchange exists without modifying the server state.

exchangeDurable :: Bool

(default True); If set when creating a new exchange, the exchange will be marked as durable. Durable exchanges remain active when a server restarts. Non-durable exchanges (transient exchanges) are purged if/when a server restarts.

exchangeAutoDelete :: Bool

(default False); If set, the exchange is deleted when all queues have finished using it.

exchangeInternal :: Bool

(default False); If set, the exchange may not be used directly by publishers, but only when bound to other exchanges. Internal exchanges are used to construct wiring that is not visible to applications.

exchangeArguments :: FieldTable

(default empty); A set of arguments for the declaration. The syntax and semantics of these arguments depends on the server implementation.

newExchange :: ExchangeOptsSource

an ExchangeOpts with defaults set; you must override at least the exchangeName and exchangeType fields.

declareExchange :: Channel -> ExchangeOpts -> IO ()Source

declares a new exchange on the AMQP server. Can be used like this: declareExchange channel newExchange {exchangeName = "myExchange", exchangeType = "fanout"}

bindExchange :: Channel -> Text -> Text -> Text -> IO ()Source

bindExchange chan destinationName sourceName routingKey binds the exchange to the exchange using the provided routing key

bindExchange' :: Channel -> Text -> Text -> Text -> FieldTable -> IO ()Source

an extended version of bindExchange that allows you to include arbitrary arguments. This is useful to use the headers exchange-type.

unbindExchange :: Channel -> Text -> Text -> Text -> IO ()Source

unbindExchange chan destinationName sourceName routingKey unbinds an exchange from an exchange. The routingKey must be identical to the one specified when binding the exchange.

unbindExchange' :: Channel -> Text -> Text -> Text -> FieldTable -> IO ()Source

an extended version of unbindExchange that allows you to include arguments. The arguments must be identical to the ones specified when binding the exchange.

deleteExchange :: Channel -> Text -> IO ()Source

deletes the exchange with the provided name

Queues

data QueueOpts Source

A record that contains the fields needed when creating a new queue using declareQueue. The default values apply when you use newQueue.

Constructors

QueueOpts 

Fields

queueName :: Text

(default ""); the name of the queue; if left empty, the server will generate a new name and return it from the declareQueue method

queuePassive :: Bool

(default False); If set, the server will not create the queue. The client can use this to check whether a queue exists without modifying the server state.

queueDurable :: Bool

(default True); If set when creating a new queue, the queue will be marked as durable. Durable queues remain active when a server restarts. Non-durable queues (transient queues) are purged if/when a server restarts. Note that durable queues do not necessarily hold persistent messages, although it does not make sense to send persistent messages to a transient queue.

queueExclusive :: Bool

(default False); Exclusive queues may only be consumed from by the current connection. Setting the exclusive flag always implies 'auto-delete'.

queueAutoDelete :: Bool

(default False); If set, the queue is deleted when all consumers have finished using it. Last consumer can be cancelled either explicitly or because its channel is closed. If there was no consumer ever on the queue, it won't be deleted.

queueHeaders :: FieldTable

(default empty): Headers to use when creating this queue, such as x-message-ttl or x-dead-letter-exchange.

newQueue :: QueueOptsSource

a QueueOpts with defaults set; you should override at least queueName.

declareQueue :: Channel -> QueueOpts -> IO (Text, Int, Int)Source

creates a new queue on the AMQP server; can be used like this: declareQueue channel newQueue {queueName = "myQueue"}.

Returns a tuple (queue, messageCount, consumerCount). queue is the name of the new queue (if you don't specify a queue the server will autogenerate one). messageCount is the number of messages in the queue, which will be zero for newly-created queues. consumerCount is the number of active consumers for the queue.

bindQueue :: Channel -> Text -> Text -> Text -> IO ()Source

bindQueue chan queue exchange routingKey binds the queue to the exchange using the provided routing key. If exchange is the empty string, the default exchange will be used.

bindQueue' :: Channel -> Text -> Text -> Text -> FieldTable -> IO ()Source

an extended version of bindQueue that allows you to include arbitrary arguments. This is useful to use the headers exchange-type.

unbindQueue :: Channel -> Text -> Text -> Text -> IO ()Source

unbindQueue chan queue exchange routingKey unbinds a queue from an exchange. The routingKey must be identical to the one specified when binding the queue.

unbindQueue' :: Channel -> Text -> Text -> Text -> FieldTable -> IO ()Source

an extended version of unbindQueue that allows you to include arguments. The arguments must be identical to the ones specified when binding the queue.

purgeQueue :: Channel -> Text -> IO Word32Source

remove all messages from the queue; returns the number of messages that were in the queue

deleteQueue :: Channel -> Text -> IO Word32Source

deletes the queue; returns the number of messages that were in the queue before deletion

Messaging

data Message Source

An AMQP message

Constructors

Message 

Fields

msgBody :: ByteString

the content of your message

msgDeliveryMode :: Maybe DeliveryMode

see DeliveryMode

msgTimestamp :: Maybe Timestamp

use in any way you like; this doesn't affect the way the message is handled

msgID :: Maybe Text

use in any way you like; this doesn't affect the way the message is handled

msgContentType :: Maybe Text
 
msgReplyTo :: Maybe Text
 
msgCorrelationID :: Maybe Text
 
msgHeaders :: Maybe FieldTable
 

data DeliveryMode Source

Constructors

Persistent

the message will survive server restarts (if the queue is durable)

NonPersistent

the message may be lost after server restarts

newMsg :: MessageSource

a Msg with defaults set; you should override at least msgBody

data Envelope Source

contains meta-information of a delivered message (through getMsg or consumeMsgs)

data Ack Source

specifies whether you have to acknowledge messages that you receive from consumeMsgs or getMsg. If you use Ack, you have to call ackMsg or ackEnv after you have processed a message, otherwise it might be delivered again in the future

Constructors

Ack 
NoAck 

Instances

consumeMsgs :: Channel -> Text -> Ack -> ((Message, Envelope) -> IO ()) -> IO ConsumerTagSource

consumeMsgs chan queue ack callback subscribes to the given queue and returns a consumerTag. For any incoming message, the callback will be run. If ack == Ack you will have to acknowledge all incoming messages (see ackMsg and ackEnv)

NOTE: The callback will be run on the same thread as the channel thread (every channel spawns its own thread to listen for incoming data) so DO NOT perform any request on chan inside the callback (however, you CAN perform requests on other open channels inside the callback, though I wouldn't recommend it). Functions that can safely be called on chan are ackMsg, ackEnv, rejectMsg, recoverMsgs. If you want to perform anything more complex, it's a good idea to wrap it inside forkIO.

consumeMsgs' :: Channel -> Text -> Ack -> ((Message, Envelope) -> IO ()) -> FieldTable -> IO ConsumerTagSource

an extended version of consumeMsgs that allows you to include arbitrary arguments.

cancelConsumer :: Channel -> ConsumerTag -> IO ()Source

stops a consumer that was started with consumeMsgs

publishMsg :: Channel -> Text -> Text -> Message -> IO ()Source

publishMsg chan exchange routingKey msg publishes msg to the exchange with the provided exchange. The effect of routingKey depends on the type of the exchange.

NOTE: This method may temporarily block if the AMQP server requested us to stop sending content data (using the flow control mechanism). So don't rely on this method returning immediately.

publishMsg' :: Channel -> Text -> Text -> Bool -> Message -> IO ()Source

Like publishMsg, but additionally allows you to specify whether the mandatory flag should be set.

getMsg :: Channel -> Ack -> Text -> IO (Maybe (Message, Envelope))Source

getMsg chan ack queue gets a message from the specified queue. If ack==Ack, you have to call ackMsg or ackEnv for any message that you get, otherwise it might be delivered again in the future (by calling recoverMsgs)

rejectMsg :: Channel -> LongLongInt -> Bool -> IO ()Source

rejectMsg chan deliveryTag requeue allows a client to reject a message. It can be used to interrupt and cancel large incoming messages, or return untreatable messages to their original queue. If requeue==False, the message will be discarded. If it is True, the server will attempt to requeue the message.

NOTE: RabbitMQ 1.7 doesn't implement this command

rejectEnvSource

Arguments

:: Envelope 
-> Bool

requeue

-> IO () 

Reject a message. This is a wrapper for rejectMsg in case you have the Envelope at hand.

recoverMsgs :: Channel -> Bool -> IO ()Source

recoverMsgs chan requeue asks the broker to redeliver all messages that were received but not acknowledged on the specified channel. If requeue==False, the message will be redelivered to the original recipient. If requeue==True, the server will attempt to requeue the message, potentially then delivering it to an alternative subscriber.

ackMsg :: Channel -> LongLongInt -> Bool -> IO ()Source

ackMsg chan deliveryTag multiple acknowledges one or more messages. A message MUST not be acknowledged more than once.

if multiple==True, the deliverTag is treated as "up to and including", so that the client can acknowledge multiple messages with a single method call. If multiple==False, deliveryTag refers to a single message.

If multiple==True, and deliveryTag==0, tells the server to acknowledge all outstanding mesages.

ackEnv :: Envelope -> IO ()Source

Acknowledges a single message. This is a wrapper for ackMsg in case you have the Envelope at hand.

Transactions

txSelect :: Channel -> IO ()Source

This method sets the channel to use standard transactions. The client must use this method at least once on a channel before using the Commit or Rollback methods.

txCommit :: Channel -> IO ()Source

This method commits all messages published and acknowledged in the current transaction. A new transaction starts immediately after a commit.

txRollback :: Channel -> IO ()Source

This method abandons all messages published and acknowledged in the current transaction. A new transaction starts immediately after a rollback.

Flow Control

flow :: Channel -> Bool -> IO ()Source

flow chan active tells the AMQP server to pause or restart the flow of content data. This is a simple flow-control mechanism that a peer can use to avoid overflowing its queues or otherwise finding itself receiving more messages than it can process.

If active==True the server will start sending content data, if active==False the server will stop sending content data.

A new channel is always active by default.

NOTE: RabbitMQ 1.7 doesn't implement this command.

SASL

data SASLMechanism Source

A SASLMechanism is described by its name (saslName), its initial response (saslInitialResponse), and an optional function (saslChallengeFunc) that transforms a security challenge provided by the server into response, which is then sent back to the server for verification.

Constructors

SASLMechanism 

Fields

saslName :: !Text

mechanism name

saslInitialResponse :: !ByteString

initial response

saslChallengeFunc :: !(Maybe (ByteString -> IO ByteString))

challenge processing function

plain :: Text -> Text -> SASLMechanismSource

The PLAIN SASL mechanism. See RFC4616

rabbitCRdemo :: Text -> Text -> SASLMechanismSource

The RABBIT-CR-DEMO SASL mechanism needs to be explicitly enabled on the RabbitMQ server and should only be used for demonstration purposes of the challenge-response cycle. See http://www.rabbitmq.com/authentication.html.

Exceptions

data AMQPException Source

Constructors

ChannelClosedException String

the String contains the reason why the channel was closed

ConnectionClosedException String

String may contain a reason

URI parsing

fromURI :: String -> ConnectionOptsSource

Parses amqp standard URI of the form amqp:user:passwordhost:port/vhost and returns a ConnectionOpts for use with openConnection'' | Any of these fields may be empty and will be replaced with defaults from amqp:guest:guestlocalhost:5672/