Amqp Broker
Amqp Broker
Amqp Broker
Track changes is on
Table of Contents
1 Overview........................................................................................................................3
1.1 What is a broker?....................................................................................................3
1.2 Relation to the other books.....................................................................................3
2 Client to broker protocol................................................................................................5
2.1 Messages.................................................................................................................5
2.2 Links........................................................................................................................6
3 Transactions.................................................................................................................15
3.1 Transactional publish............................................................................................15
3.2 Transactional accept.............................................................................................17
3.3 Transactional acquire............................................................................................19
3.4 Failed transaction..................................................................................................19
4 Broker model................................................................................................................21
4.1 Addresses and aliases...........................................................................................21
4.2 Visibility.................................................................................................................21
4.3 Topics and Queues................................................................................................21
4.4 Bindings................................................................................................................22
4.5 Lifetime ................................................................................................................22
5 Examples.....................................................................................................................23
5.1 Exchanges and Queues.........................................................................................23
5.2 Request/Reply.......................................................................................................23
5.3 Publish/Subscribe..................................................................................................23
6 For future consideration...............................................................................................24
6.1 Serialisation...........................................................................................................24
6.2 Exclusivity.............................................................................................................24
local=NULL, remote=(X, Y) "There is no link here". Used to close a link, destroying it.
local=NULL, remote=NULL "There is no link here, and I know of no link there". This is
probably a reply to local=NULL, remote=(X, Y), or it may
be used by a client that has forgotten the remote state.
local=(A, B), remote=(X, Y) “There is a link here and I know of a link there”. Usually
sent as a response to local=(X, Y), remote=NULL, or to re-
establish a link.
If a broker cannot honour a link as specified by a client, it MUST respond with either a
null target in local (for links in which it is the receiver) or a null source in local (for links in
which it is the sender). This is referred to as “refusing a link”, and should be regarded by
the client as a failure to establish the link.
When establishing a new link, some fields are expected to be supplied definitively by the
client; some are expected to be supplied by the client as an indication of its
requirements of the broker; and some must be left null for the broker to supply
definitively.
Field Supplied by
options May be supplied by the client. For some values, the broker may
refuse the link; the broker may not add values.
The broker may refuse links based on the value supplied in local
by the client.
remote Must be supplied by the broker and echo the local given in the
request.
1
transfer-count is calculated using the value of transfer-unit. In some circumstances,
clients may wish to send attach then transfer without waiting for a corresponding attach,
and thereby will not have the authoritative value for transfer-unit with which to calculate
the transfer-count sent with the transfer. In this case, the client SHOULD send null for the
transfer-unit; a broker MAY then choose to honour the transfer, supply the transfer-unit
with its response, and expect the client to recalculate the transfer-count subsequently.
giving the outcome and asserting that the transfer is settled. A disposition MAY be sent if
a state is not given in the transfer; otherwise, the outcome is that given as the default-
outcome.
A peer MUST treat conflicting statements of the outcome for a transfer as an error. For
example, if a client sends an accepted outcome then a rejected outcome for a particular
transfer, the broker must close the link or session, reporting an error; and vice versa.
The exception to this is the provisional outcome given for a transfer in the scope of a
transaction, which may change once the transaction is discharged.
2.2.5 Transfer failures
The messaging model admits varieties of responsibility transfer. Central to this is the
idea of settlement; that is, agreement on a particular outcome for a transfer. However,
the receiver of a link can disappear without responding and not come back (i.e., time out)
without the outcome being settled; we need to account for what happens to messages
that have been committed for transfer over that link, but which are not known to have
been transferred successfully because the outcome has not been settled.
The source type in book IV defines an default-outcome field, which gives the assumed
outcome for transfers left unsettled.
Generally speaking, there are four options for dealing with unsettled messages:
1. Try to deliver the message to some other link from the node, or re-queue it;
the default-outcome is released
2. Send the message to a “Dead letter queue”; default-outcome of reject
3. Return the message to the publisher, given a suitable return route; default-
outcome of reject
4. Abandon the delivery; in this case, the default-outcome is accepted.
A client may supply null in default-outcome, indicating that it agrees with whichever
default-outcome the broker supplies; or, it may supply a default-outcome to indicate its
expected behaviour.
A broker MUST enforce its policy or configuration where present by refusing links that do
not agree on the default-outcome.
2.2.6 Publishing
Publishing a message requires a link established with the client as sender and broker as
receiver. Broadly speaking, there are two styles of arranging this:
• one-off; i.e., establishing a link and transferring one (or perhaps a small handful)
message, then closing the link; and,
• continuous, that is, establishing a long-lived link and transferring many messages.
It is desirable, for the first scenario especially, to be able to establish a link, transfer a
message, and possibly even close the link without having to wait for a response from the
broker. For this reason, a broker MAY choose to tolerate incorrect flow state for transfers
along new links, as described in 2.2.1.
If a client wishes to receive acknowledgement for a transfer, it is enough to supply a
state (or rely on the default outcome) and the value false for settled. The broker is then
obliged to settle the transfer.
Attach(options=None,
name="publish-link-1234",
handle=4,
flow_state=FlowState( # Session-level low water mark. Here
unsettled_lwm=1, # we are starting from scratch, so we
session_credit=10, # say the LWM is the next transfer-id.
transfer_count=0,
link_credit=None,
available=None,
drain=False),
role=False, # We are a sender.
local=Linkage( # Here we are saying that the broker
source=Source( # can simply advance the LWM to
outcomes=[“amqp:accept:map”], # indicate that it has accepted
default_outcome=Accept()), # messages, since there is only one
# possible outcome. This is
# effectively “at most once”, since
# a dropped connection will settle
# transfers to the default outcome.
target=Target(address="my_topic")), # Where we would like to publish to.
remote=None,
transfer_unit=None, # We'll be told by the broker when it
max_message_size=0, # responds.
error_mode="detach") # If do something wrong, the link
# should be
detached by the broker.
Attach(options=None,
name="publish-link-1234", # The broker has its own handle, which
handle=5, # we have to recognise.
flow_state=FlowState(
unsettled_lwm=1, # We told the broker these, and
session_credit=10, # nothing has
transfer_count=0, been sent yet, so it
# remains the
same.
link_credit=10), # The broker gives us some initial
role=True, # credit, with which to transfer
# messages.
local=Linkage(Source( # The broker agrees on the linkage.
outcomes=[“amqp:accept:map”], # If it did not, it would have to
default_outcome=Accept()), # refuse the link by giving a null
target=Target(address="my_topic")), # target here.
remote=Linkage(
source=Source(
outcomes=[“amqp:accept:map”],
default_outcome=Accept()),
target=Target(address="my_topic")),
expiry_policy="session", # The broker tells us its defaults
timeout=0, # where we have not supplied values.
unsettled=None,
transfer_unit=0,
max_message_size=0,
error_mode="detach")
# We now have a link, targeting
# "my_topic". We use the handle 4 and
# the broker uses the handle 5.
Transfer(options=None, # We'll transfer a message.
handle=4, # This is our alias for the link.
flow_state=FlowState(
unsettled_lwm=1, # The LWM refers to this transfer
session_credit=9, # By sending an unsettled transfer,
transfer_count=1, # we are reducing the session credit.
link_credit=9, # We reduce our credit by the “size”
available=None, # of this transfer.
drain=False),
delivery_tag="delivery123", # delivery-tag is arbitrary, but
transfer_id=1, # transfer-id is a serial number. It
# corresponds to our LWM above.
settled=False, # We will be waiting for the broker
state=None, # to settle this. We don't need to
resume=False, # supply a state, since there is only
more=False, # one outcome possible and we're not
aborted=False, # using a transaction.
batchable=False,
fragments=[...]) # Our message (elided here)
# The broker is obliged to respond as
# soon as possible, since we said
# batchable is false. It does not need
# to send a disposition frame, though;
# it can get away with a flow frame.
Flow(handle=5, # The broker's handle for the link
flow_state=FlowState(
unsettled_lwm=2, # The broker advanced the LWM to
session_credit=10, # indicate that it considers the
transfer_count=1, # transfer above to be settled. We now
link_credit=9)) # consider the transfer to have the
# default-outcome.
Attach(name="subscribe-link-1234",
handle=15,
role=True, # We are the receiver.
local=Linkage(target=None, # The target is unimportant.
source=Source(
address="my_topic", # Names the source
dynamic=None, # It's a well-known address.
distribution_mode="copy", # We are expecting this to be a
# subscription
default_outcome=Accept(), # Messages implicitly settled should be
# accepted, and
outcomes=["amqp:accept:map"])), # we will only ever accept transfers.
# The broker can settle transfers
# immediately, since there is only one
# possible outcome for a message.
remote=None) # (For the broker to supply)
Attach(name="subscribe-link-1234",
handle=11, # The broker's handle for the link.
role=False, # The broker is the sender.
local=Linkage(target=None, # The broker confirms the link target
source=Source( # and source, to show the link is
address="my_topic", # established
dynamic=None,
distribution_mode="copy",
default_outcome=Accept(),
outcomes=["amqp:accept:map"])),
remote=Linkage(target=None, # This is an echo of the local
source=Source(address="my_topic", # field supplied by the client.
dynamic=None,
distribution_mode="copy",
default_outcome=Accept(),
outcomes=["amqp:accept:map"])),
Table 4: Subscribing
2.2.9.2 Consumers
Consumers use outcomes as instructions. Specifically,
• accepted instructs the broker to not transfer the message again;
• release instructs the broker to redistribute the message;
• reject instructs the broker to invoke rejected message handling e.g., sending
the message to a dead letter queue;
• modified instructs the broker to reconsider the message, with header
alterations, for distribution.
Brokers MUST indicate the outcomes available in the outcomes field of the source, when
responding to the client during link establishment.
A client MAY itself specify a set of the outcomes during link establishment; in this case,
the client is specifying that it will only use certain outcomes. If this is not a subset of
those supported by the broker, it MUST refuse the link. If it is, the broker MUST echo the
outcomes in its response.
If the client then gives an outcome not in the set, the broker MUST raise an error.
Attach(name="consume-link-1234",
handle=15,
role=True, # We are the receiver.
local=Linkage(target=None, # The target is unimportant.
source=Source(
address="my_queue", # Names the source
dynamic=None, # It's a well-known address.
distribution_mode="move", # We are expecting to be a
# de-queueing messages
default_outcome=Release(), # Messages implicitly settled should be
# released; however,
outcomes=["amqp:accept:map"])), # we will only ever accept transfers.
# The broker can assume “accept” as the
# state, but cannot immediately settle
# transfers.
remote=None) # (For the broker to supply)
Attach(name="consume-link-1234",
handle=11, # The broker's handle for the link.
role=False, # The broker is the sender.
local=Linkage(target=None, # The broker confirms the link target
source=Source( # and source, to show the link is
address="my_queue", # established
dynamic=None,
distribution_mode="move",
default_outcome=Release(),
outcomes=["amqp:accept:map"])),
remote=Linkage(target=None, # This is an echo of the local
source=Source(address="my_queue", # field supplied by the client.
dynamic=None,
distribution_mode="move",
default_outcome=Release(),
outcomes=["amqp:accept:map"])),
Table 5: Consuming
2.2.10Browsing
Various use cases require the ability to receive messages from a node without interacting
with its distribution of messages. This is partially encoded in the protocol by a link source
specifying a distribution-mode of copy (when it would otherwise be expected to be
move); move meaning that the link is considered when distributing messages, and copy
meaning in this case that it is considered in addition to distributing messages.
The semantics for outcomes are the same as for other links specifying copy in the
source.
2.2.11Dynamic sources and targets
A broker may support the creation of dynamic sources or targets, or both. If so, a client
MAY use the dynamic field to request such a source or target. Aside from the lifetime
given in dynamic, the nature of the source or target is undefined.
The lifetime defines the earliest point at which the dynamic source or target may be
destroyed. Where the lifetime is bounded by an explicit action of the client (e.g., link
closure using detach), the destruction SHOULD be enacted before the broker responds to
the action (in this example, before it sends the corresponding link detach).
3 Transactions
A broker MAY act in the role of transactional resource manager, enacting units of work
durably and atomically. What “durably” entails depends on the broker policy or
configuration and the source or target; a working principle is that the relevant state has
been “safely” stored; e.g., to disk. “Atomically” has the usual sense, that is, the entire
unit of work is completed or none of it is.
A broker MAY also act as a transaction co-ordinator if it at least supports local
transactions. In this case it MUST recognise the transaction coordinator target as defined
in book V. When establishing a link to the coordinator target, a client MAY omit the
source field.
Settlement and transactions are related; a broker MUST not settle an outcome before the
transaction with which it is associated has been discharged.
A broker MAY indicate a provisional outcome in the context of a transaction by sending
disposition with an unsettled transfer-state. If this is done, the broker MUST honour that
indication with its settled outcome once the transaction is discharged, or fail to discharge
the transaction.
Thus, if a receiver sends an unsettled transfer-state in the context of a transaction, it
MUST NOT be treated as part of a settlement exchange; e.g., the sender MUST also wait
until the transaction is discharged before settling transfers.
In the case of a failed transaction, it is understood that transfers, dispositions, and
transfers in response to flow-control are rolled back. It is not necessary to exchange
transfer-state. Flow-control state is not rolled back; e.g., transfers that are part of a failed
transaction still consume credit.
3.1 Transactional publish
In this example we show a protocol exchange for a client transactionally publishing to a
broker. The connection and session establishment are assumed, and flow control and
other irrelevant details are elided.
Generally the frames are asynchronous; however, there are certain points at which the
client has to wait for a response in order to proceed; e.g., when declaring a transaction,
the client as transaction controller needs the transaction ID from the response in order to
use it with the transfer that follows. Below, the frames are shown in request/response
order to aid reading.
# First we establish a link to
# the transaction coordinator.
Attach(name="txn-link-1234",
handle=4, # Our handle for the link.
role=False, # We are the sender.
local=Linkage(
source=None,
target=Coordinator( # We are asking for a link to
capabilities=["amqp:local-transactions"])), # the transaction coordinator,
remote=None) # and for it to support local
# transactions.
Attach(name="txn-link-1234", # The broker echoes the name,
handle=5, # and gives its handle.
role=True, # Broker is the receiver.
local=Linkage( # The broker says that it
source=None, # does have a transactional
target=Coordinator( # coordinator, and that it
capabilities=["amqp:local-transactions", # supports these transactional
"amqp:distributed-transactions", # modes.
"amqp:promotable-transactions"])),
remote=Linkage( # The broker echoes back our
source=None, # statement of the linkage.
target=Coordinator(
capabilities=["amqp:local-transactions"])))
# Now we have a link to the
# transaction co-ordinator, with
# handle 4 for send and handle 5
# for receive.
Transfer(handle=4, # Our handle to the coordinator
delivery_tag="begin321", # This is arbitrary
transfer_id=16, # This is a serial number alias
settled=False, # We expect confirmation
state=TransferState(outcome=Accepted()), # from the broker.
fragments=[Fragment(
format_code=4, # amqp-data
first=True, # NB: in general, payloads are
last=True, # encoded and sent as a binary
payload_offset=0,
payload=Declare( # Let the broker create a local
global_txn_id=None))]) # transaction ID
Disposition(role=True, # The broker is the receiver
extents=[Extent(
first=16,
last=16, # Alias of transfer just made