이 콘텐츠는 선택한 언어로 제공되지 않습니다.
Chapter 4. Addresses, Queues, and Topics
AMQ Broker has a unique addressing model that is both powerful and flexible and that offers great performance. The addressing model comprises three main concepts: addresses, queues and routing types.
An address represents a messaging endpoint. Within the configuration, a typical address is given a unique name, 0 or more queues, and a routing type.
A queue is associated with an address. There can be multiple queues per address. Once an incoming message is matched to an address, the message is sent on to one or more of its queues, depending on the routing type configured. Queues can be configured to be automatically created and deleted. You can also configure an address (and hence its associated queues) as durable. Messages in a durable queue can survive a crash or restart of the broker, as long as the messages in the queue are also persistent. By contrast, messages in a non-durable queue do not survive a crash or restart of the broker, even if the messages themselves are persistent.
A routing type determines how messages are sent to the queues associated with an address. A AMQ Broker address can be configured with two different routing types.
If you want your messages routed to… | Use this routing type … |
---|---|
A single queue within the matching address, in a point-to-point manner. | anycast |
Every queue within the matching address, in a publish-subscribe manner. | multicast |
An address must have at least one routing type.
It is possible to define more than one routing type per address, but this typically results in an anti-pattern and is therefore not recommended.
If an address does use both routing types, however, and the client does not show a preference for either one, the broker typically defaults to the anycast
routing type. The one exception is when the client uses the MQTT protocol. In that case, the default routing type is multicast
.
4.1. Address and Queue Naming Requirements
You should be aware of the following requirements when you configure addresses and queues:
To ensure that a client can connect to a queue regardless of which wire protocol it uses, your address and queue names should not include any of the following characters:
&
::
,
?
>
-
The
#
and*
characters are reserved for wildcard expressions. For more information, see the section called “AMQ Broker Wildcard Syntax”. - Address and queue names should not include any spaces.
-
To separate words in an address or queue name, use the configured delimiter character (the default is the
.
character). For more information, see the section called “AMQ Broker Wildcard Syntax”.
4.2. Configuring Point-to-Point Messaging
Point-to-point messaging is a common scenario in which a message sent by a producer has only one consumer. AMQP and JMS message producers and consumers can make use of point-to-point messaging queues, for example. Define an anycast
routing type for an address
so that its queues receive messages in a point-to-point manner.
When a message is received on an address using anycast
, AMQ Broker locates the queue associated with the address and routes the message to it. When consumers request to consume from the address, the broker locates the relevant queue and associates this queue with the appropriate consumers. If multiple consumers are connected to the same queue, messages are distributed amongst each consumer equally, providing the consumers are equally able to handle them.
Figure 4.1. Point-to-Point
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Wrap an
anycast
configuration element around the chosenqueue
element of anaddress
. Ensure the value ofaddress name
andqueue name
elements are same.<configuration ...> <core ...> ... <address name="durable"> <anycast> <queue name="durable"/> </anycast> </address> </core> </configuration>
4.3. Configuring Publish-Subscribe Messaging
In a publish-subscribe scenario, messages are sent to every consumer subscribed to an address. JMS topics and MQTT subscriptions are two examples of publish-subscribe messaging. When a message is received on an address with a multicast
routing type, AMQ Broker routes a copy of the message to each queue. To reduce the overhead of copying, each queue is sent only a reference to the message and not a full copy.
Figure 4.2. Publish-Subscribe
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add an empty
multicast
configuration element to the chosen address.<configuration ...> <core ...> ... <address name="topic.foo"> <multicast/> </address> </core> </configuration>
(Optional) Add one more
queue
elements to the address and wrap themulticast
element around them. This step is typically not needed since the broker automatically creates a queue for each subscription requested by a client.<configuration ...> <core ...> ... <address name="topic.foo"> <multicast> <queue name="client123.topic.foo"/> <queue name="client456.topic.foo"/> </multicast> </address> </core> </configuration>
4.4. Configuring a Point-to-Point Using Two Queues
You can define more than one queue on an address by using an anycast
routing type. Messages semt to an anycast
address are distributed evenly across all associated queues. By using Fully Qualified Queue Names, which are described later, you can have clients connect to a specific queue. If more than one consumer connects to the same queue, AMQ Broker distributes messages between them.
Figure 4.3. Point-to-Point with Two Queues
This is how AMQ Broker handles load balancing of queues across multiple nodes in a cluster.
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Wrap an
anycast
configuration element around thequeue
elements in theaddress
.<configuration ...> <core ...> ... <address name="address.foo"> <anycast> <queue name="q1"/> <queue name="q2"/> </anycast> </address> </core> </configuration>
4.5. Using Point-to-Point and Publish-Subscribe Together
It is possible to define an address with both point-to-point and publish-subscribe semantics enabled. While not typically recommended, this can be useful when you want, for example, a JMS Queue named orders
and a JMS topic named orders
. The different routing types make the addresses appear to be distinct.
Using an example of JMS clients, the messages sent by a JMS queue producer are routed using the anycast
routing type. Messages sent by a JMS topic producer uses the multicast
routing type. In addition, when a JMS topic consumer attaches, it is attached to its own subscription queue. The JMS queue consumer, however, is attached to the anycast
queue.
Figure 4.4. Point-to-Point and Publish-Subscribe
The behavior in this scenario is dependent on the protocol being used. For JMS there is a clear distinction between topic and queue producers and consumers, which makes the logic straightforward. Other protocols like AMQP do not make this distinction. A message being sent via AMQP is routed by both anycast
and multicast
and consumers default to anycast
. For more information, check the behavior of each protocol in the sections on protocols.
The XML excerpt below is an example of what the configuration for an address using both anycast
and multicast
routing types would look like in BROKER_INSTANCE_DIR/etc/broker.xml
. Note that subscription queues are typically created on demand, so there is no need to list specific queue
elements inside the multicast
routing type.
<configuration ...> <core ...> ... <address name="foo.orders"> <anycast> <queue name="orders"/> </anycast> <multicast/> </address> </core> </configuration>
4.6. Configuring Subscription Queues
In most cases it is not necessary to pre-create subscription queues because protocol managers create subscription queues automatically when clients first request to subscribe to an address. See Protocol Managers and Addresses for more information. For durable subscriptions, the generated queue name is usually a concatenation of the client id and the address.
Configuring a Durable Subscription Queue
When an queue is configured as a durable subscription, the broker saves messages for any inactive subscribers and delivers them to the subscribers when they reconnect. Clients are therefore guaranteed to receive each message delivered to the queue after subscribing to it.
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add the
durable
configuration element to the chosenqueue
and assign it a value oftrue
.<configuration ...> <core ...> ... <address name="durable.foo"> <multicast> <queue name="q1"> <durable>true</durable> </queue> </multicast> </address> </core> </configuration>
Configuring a Non-Shared Durable Subscription
The broker can be configured to prevent more than one consumer from connecting to a queue at any one time. The subscriptions to queues configured this way are therefore "non-shared".
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add the
durable
configuration element to each chosen queue.<configuration ...> <core ...> ... <address name="non.shared.durable.foo"> <multicast> <queue name="orders1"> <durable>true</durable> </queue> <queue name="orders2"> <durable>true</durable> </queue> </multicast> </address> </core> </configuration>
Add the
max-consumers
attribute to each chosenqueue
element and assign it a value of1
.<configuration ...> <core ...> ... <address name="non.shared.durable.foo"> <multicast> <queue name="orders1" max-consumers="1"> <durable>true</durable> </queue> <queue name="orders2" max-consumers="1"> <durable>true</durable> </queue> </multicast> </address> </core> </configuration>
Configuring a Non-Durable Subscription Queue
Non-durable subscriptions are usually managed by the relevant protocol manager, which creates and deletes temporary queues.
However, if you want to pre-create a queue that behaves like a non-durable subscription queue, you can use the purge-on-no-consumers
attribute on the queue. When purge-on-no-consumers
is set to true
, the queue does not start receiving messages until a consumer is attached. In addition, when the last consumer is detached from the queue, the queue is purged (that is, its messages are removed). The queue does not receive any further messages until a new consumer is attached to the queue.
Procedure
-
Open the file
BROKER_INSTANCE_DIR/etc/broker.xml
for editing. Add the
purge-on-no-consumers
attribute to each chosenqueue
element. Setpurge-on-no-consumers
totrue
.<configuration ...> <core ...> ... <address name="non.durable.foo"> <multicast> <queue name="orders1" purge-on-no-consumers="true"/> </multicast> </address> </core> </configuration>
4.7. Using a Fully Qualified Queue Name
Internally the broker maps a client’s request for an address to specific queues. The broker decides on behalf of the client which queues to send messages, or from which queue to receive messages. However, more advanced use cases might require that the client specify a queue directly. In these situations the client can use a Fully Qualified Queue Name (FQQN), by specifying both the address name and the queue name, separated by a ::
.
Prerequisites
An address is configured with two or more queues. In the example below the address
foo
has two queues,q1
andq2
.<configuration ...> <core ...> ... <addresses> <address name="foo"> <anycast> <queue name="q1" /> <queue name="q2" /> </anycast> </address> </addresses> </core> </configuration>
Procedure
In the client code, use both the address name and the queue name when requesting a connection from the broker. Remember to use two colons,
::
, to separate the names, as in the example Java code below.String FQQN = "foo::q1"; Queue q1 session.createQueue(FQQN); MessageConsumer consumer = session.createConsumer(q1);
4.8. Configuring Sharded Queues
A common pattern for processing of messages across a queue where only partial ordering is required is to use queue sharding. In AMQ Broker this can be achieved by creating an anycast
address that acts as a single logical queue, but which is backed by many underlying physical queues.
Procedure
Open
BROKER_INSTANCE_DIR/etc/broker.xml
and add anaddress
with the desired name. In the example below theaddress
namedsharded
is added to the configuration.<configuration ...> <core ...> ... <addresses> <address name="sharded"></address> </addresses> </core> </configuration>
Add the
anycast
routing type and include the desired number of sharded queues. In the example below, the queuesq1
,q2
, andq3
are added asanycast
destinations.<configuration ...> <core ...> ... <addresses> <address name="sharded"> <anycast> <queue name="q1" /> <queue name="q2" /> <queue name="q3" /> </anycast> </address> </addresses> </core> </configuration>
Using the configuration above, messages sent to sharded
are distributed equally across q1
, q2
and q3
. Clients are able to connect directly to a specific physical queue when using a fully qualified queue name and receive messages sent to that specific queue only.
To tie particular messages to a particular queue, clients can specify a message group for each message. The broker routes grouped messages to the same queue, and one consumer processes them all. See the chapter on Message Grouping for more information.
4.9. Configuring Last Value Queues
A last value queue is a type of queue that discards messages in the queue when a newer message with the same last value property name is placed in the queue. Through this behavior, last value queues retain only the last values for messages of the same property.
A simple use case for a last value queue is for monitoring stock prices, where only the latest value for a particular stock is of interest.
The broker delivers messages that are sent to a last value queue without a configured last value property as normal messages. Such messages are not purged from the queue when a new message with a configured last value property arrives.
You can configure last value queues using:
-
The
broker.xml
configuration file - The JMS client
- The Core API
- Address wildcards
For each of the above methods, apart from the Core API, you can specify a custom value for the last value key (also called the last value property), or leave this value unset, meaning that the key is set to the default value instead. The default value for the last value key is _AMQ_LVQ_NAME
.
For the Core API, you create last value queues using the constant last value key Message.HDR_LAST_VALUE_NAME
to identify last value messages.
4.9.1. Configuring Last Value Queues Using broker.xml
To specify a custom value for the last value key, include lines in your broker.xml
configuration file that look like the following:
<address name="my.address"> <multicast> <queue name="prices1" last-value-key="stock_ticker"/> </multicast> </address>
Alternatively, you can configure a last value queue that uses the default last value key name of _AMQ_LVQ_NAME
. To do this, set the last-value configuration parameter to true in your broker.xml
configuration file, without specifying a value for the last value key. An example of this configuration is shown below.
<address name="my.address"> <multicast> <queue name="prices1" last-value="true"/> </multicast> </address>
4.9.2. Configuring Last Value Queues Using the JMS Client
When using the JMS Client to auto-create destinations used by a consumer, you can specify a last value key as part of the address settings. In this case, the auto-created queues are last value queues. An example of this configuration is shown below.
Queue queue = session.createQueue("my.destination.name?last-value-key=stock_ticker"); Topic topic = session.createTopic("my.destination.name?last-value-key=stock_ticker");
Alternatively, configure a last value queue that uses the default last value key name of _AMQ_LVQ_NAME
. To do this, set the last-value configuration parameter to true, without specifying a value for the last value key. An example of this configuration is shown below.
Queue queue = session.createQueue("my.destination.name?last-value=true"); Topic topic = session.createTopic("my.destination.name?last-value=true");
4.9.3. Configuring Last Value Queues Using the Core API
To create a last value queue using the Core API, set the lastvalue
parameter to true
when creating a queue. To do this, use the createQueue
method of the ClientSession
interface. The syntax for creating a last value queue using this method is shown below.
void createQueue( SimpleString address, RoutingType routingType, SimpleString queueName, SimpleString filter, Boolean durable, Boolean autoCreated, int maxConsumers, Boolean purgeOnNoConsumers, Boolean exclusive, Boolean lastValue )
In this case, the API uses the constant Message.HDR_LAST_VALUE_NAME
to identify last value messages delivered to the queue.
Additional Resources
-
For more information about using the
createQueue
method of the Core API to create a last value queue, see createQueue.
4.9.4. Configuring Last Value Queues Using Address Wildcards
You can use address wildcards in the broker.xml
configuration file to configure last value queues for a set of addresses. An example of this configuration is shown below.
<address-setting match="lastValueQueue"> <default-last-value-key>stock_ticker</default-last-value-key> </address-setting>
By default, the value of default-last-value-key
is null
.
When using address wildcards, you can also use the default last value key name. To do this, set the default-last-value-queue
parameter to true
, without specifying a value for the last value key.
4.9.5. Example of Last Value Queue Behavior
This example shows the configuration and behavior of a last value queue.
In your broker.xml
configuration file, suppose that you have added configuration that looks like the following:
<address name="my.address"> <multicast> <queue name="prices1" last-value-key="stock_ticker"/> </multicast> </address>
The configuration shown above creates a last value queue called prices1
, with a last value key of stock_ticker
.
Now, suppose that a client sends two messages with the same last value property name to the prices1
queue, as shown below:
TextMessage message = session.createTextMessage("First message with last value property set"); message.setStringProperty("stock_ticker", "36.83"); producer.send(message);
TextMessage message = session.createTextMessage("Second message with last value property set"); message.setStringProperty("stock_ticker", "37.02"); producer.send(message);
When two messages with the same last value property name arrive to the last value queue prices1
, only the latest message remains in the queue, with the first message being purged. At the command line, you can enter the following lines to validate this behavior:
TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000); System.out.format("Received message: %s\n", messageReceived.getText());
In this example, the output you see is the second message, since both messages use the last value property and the second message was received in the queue after the first.
4.9.6. Creating Non-Destructive Consumers
When a consumer attaches to a queue, the normal behavior is that messages sent to that consumer are acquired exclusively by the consumer. When the consumer acknowledges receipt of the messages, the broker removes the messages from the queue.
An alternative way to configure a consumer is to configure it as a queue browser. In this case, the queue still sends all messages to the consumer. However the browser does not prevent other consumers from receiving the messages. In addition, the messages remain in the queue once the browser has consumed the messages. A consumer configured as a browser is an instance of a non-destructive consumer.
In the case of a last value queue, configuring all consumers as non-destructive consumers ensures that the queue always retains the most up-to-date value for every last value key. The examples in the following sub-sections show how to configure a last value queue to ensure that all consumers are non-destructive.
4.9.6.1. Configuring Non-destructive Consumers Using broker.xml
In the broker.xml
configuration file, to create a last value queue, set the non-destructive
parameter to true
. An example of this configuration is shown below.
<address name="my.address"> <multicast> <queue name="orders1" last-value-key="stock_ticker" non-destructive="true" /> </multicast> </address>
4.9.6.2. Creating Non-destructive Consumers Using the JMS Client
When using the JMS Client to auto-create destinations used by a consumer, you configure last value queue behavior and non-destructive consumers as part of the address settings. An example of this configuration is shown below.
Queue queue = session.createQueue("my.destination.name?last-value-key=stock_ticker&non-destructive=true"); Topic topic = session.createTopic("my.destination.name?last-value-key=stock_ticker&non-destructive=true");
4.9.6.3. Configuring Non-destructive Consumers Using Address Wildcards
You can use address wildcards in the broker.xml
configuration file to configure last value queues for a set of addresses. As part of this configuration, you can also specify that consumers are non destructive, by setting default-non-destructive
to true
. An example of this configuration is shown below.
<address-setting match="lastValueQueue"> <default-last-value-key>stock_ticker </default-last-value-key> <default-non-destructive>true</default-non-destructive> </address-setting>
By default, the value of default-non-destructive
is false
.
4.10. Limiting the Number of Consumers Connected to a Queue
Limit the number of consumers connected to a particular queue by using the max-consumers
attribute. Create an exclusive consumer by setting max-consumers
flag to 1
. The default value is -1
, which is sets an unlimited number of consumers.
Procedure
Open
BROKER_INSTANCE_DIR/etc/broker.xml
and add themax-consumers
attribute to the desiredqueue
. In the example below, only20
consumers can connect to the queueq3
at the same time.<configuration ...> <core ...> ... <addresses> <address name="foo"> <anycast> <queue name="q3" max-consumers="20"/> </anycast> </address> </addresses> </core> </configuration>
(Optional) Create an exclusive consumer by setting
max-consumers
to1
, as in the example below.<configuration ...> <core ...> ... <address name="foo"> <anycast> <queue name="q3" max-consumers="1"/> </anycast> </address> </core> </configuration>
(Optional) Have an unlimited number of consumers by setting
max-consumers
to-1
, as in the example below.<configuration ...> <core ...> ... <address name="foo"> <anycast> <queue name="q3" max-consumers="-1"/> </anycast> </address> </core> </configuration>
4.11. Exclusive Queues
Exclusive queues are special queues that route all messages to only one consumer at a time. This is useful when you want all messages to be processed serially by the same consumer. If there are multiple consumers on a queue only one consumer will receive messages. If this consumer disconnects then another consumer is chosen.
4.11.1. Configuring Exclusive Queues
You configure exclusive queues in the broker.xml
configuration file something like this.
<configuration ...> <core ...> ... <address name="foo.bar"> <multicast> <queue name="orders1" exclusive="true"/> </multicast> </address> </core> </configuration>
Or on auto-create when using the JMS Client by using address parameters when creating the destination used by the consumer.
Queue queue = session.createQueue("my.destination.name?exclusive=true"); Topic topic = session.createTopic("my.destination.name?exclusive=true");
4.11.2. Setting the Exclusive Queue Default
<address-setting match="myQueue"> <default-exclusive-queue>true</default-exclusive-queue> </address-setting>
The default value for default-exclusive-queue
is false
.
4.12. Configuring Ring Queues
Generally, queues in AMQ Broker use first-in, first-out (FIFO) semantics. This means that the broker adds messages to the tail of the queue and removes them from the head. A ring queue is a special type of queue that holds a specified, fixed number of messages. The broker maintains the fixed queue size by removing the message at the head of the queue when a new message arrives but the queue already holds the specified number of messages.
For example, consider a ring queue configured with a size of 3
and a producer that sequentially sends messages A
, B
, C
, and D
. Once message C
arrives to the queue, the number of messages in the queue has reached the configured ring size. At this point, message A
is at the head of the queue, while message C
is at the tail. When message D
arrives to the queue, the broker adds the message to the tail of the queue. To maintain the fixed queue size, the broker removes the message at the head of the queue (that is, message A
). Message B
is now at the head of the queue.
4.12.1. Configuring Ring Queues
This procedure shows how to configure a ring queue.
Procedure
-
Open the
BROKER_INSTANCE_DIR/etc/broker.xml
configuration file. To define a default ring size for all queues on matching addresses that don’t have an explicit ring size set, specify a value for
default-ring-size
in theaddress-setting
element. An example is shown below.<address-settings> <address-setting match="ring.#"> <default-ring-size>3</default-ring-size> </address-setting> </address-settings>
The
default-ring-size
parameter is especially useful for defining the default size of auto-created queues. The default value ofdefault-ring-size
is-1
(that is, no size limit).To define a ring size on a specific queue, add the
ring-size
parameter to thequeue
element and specify a value. An example is shown below.<addresses> <address name="myRing"> <anycast> <queue name="myRing" ring-size="5" /> </anycast> </address> </addresses>
You can update the value of ring-size
while the broker is running. The broker dynamically applies the update. If the new ring-size
value is lower than the previous value, the broker does not immediately delete messages from the head of the queue to enforce the new size. New messages sent to the queue still force the deletion of older messages, but the queue does not reach its new, reduced size until it does so naturally, through the normal consumption of messages by clients.
4.12.2. Troubleshooting Ring Queue Behavior
This section describes situations in which the behavior of a ring queue appears to differ from its configuration.
See:
4.12.2.1. In-delivery messages and rollbacks
When a message is in delivery to a consumer, the message is in an "in-between" state, where the message is technically no longer on the queue, but is also not yet acknowledged. A message remains in an in-delivery state until acknowledged by the consumer. Messages that remain in an in-delivery state cannot be removed from the ring queue.
Because the broker cannot remove in-delivery messages, a client can send more messages to a ring queue than the ring size configuration seems to allow. For example, consider this scenario:
-
A producer sends three messages to a ring queue configured with
ring-size="3"
. All messages are immediately dispatched to a consumer.
At this point,
messageCount
=3
anddeliveringCount
=3
.The producer sends another message to the queue. The message is then dispatched to the consumer.
Now,
messageCount
=4
anddeliveringCount
=4
. The message count of4
is greater than the configured ring size of3
. However, the broker is obliged to allow this situation because it cannot remove the in-delivery messages from the queue.Now, suppose that the consumer is closed without acknowledging any of the messages.
In this case, the four in-delivery, unacknowledged messages are canceled back to the broker and added to the head of the queue in the reverse order from which they were consumed. This action puts the queue over its configured ring size. Because a ring queue prefers messages at the tail of the queue over messages at the head, the queue discards the first message sent by the producer, because this was the last message added back to the head of the queue. Transaction or core session rollbacks are treated in the same way.
If you are using the core client directly, or using an AMQ Core Protocol JMS client, you can minimize the number of messages in delivery by reducing the value of the consumerWindowSize
parameter (1024 * 1024 bytes by default).
4.12.2.2. Scheduled messages
When a scheduled message is sent to a queue, the message is not immediately added to the tail of the queue like a normal message. Instead, the broker holds the scheduled message in an intermediate buffer and schedules the message for delivery onto the head of the queue, according to the details of the message. However, scheduled messages are still reflected in the message count of the queue. As with in-delivery messages, this behavior can make it appear that the broker is not enforcing the ring queue size. For example, consider this scenario:
At 12:00, a producer sends a message,
A
, to a ring queue configured withring-size="3"
. The message is scheduled for 12:05.At this point,
messageCount
=1
andscheduledCount
=1
.At 12:01, producer sends message
B
to the same ring queue.Now,
messageCount
=2
andscheduledCount
=1
.At 12:02, producer sends message
C
to the same ring queue.Now,
messageCount
=3
andscheduledCount
=1
.At 12:03, producer sends message
D
to the same ring queue.Now,
messageCount
=4
andscheduledCount
=1
.The message count for the queue is now
4
, one greater than the configured ring size of3
. However, the scheduled message is not technically on the queue yet (that is, it is on the broker and scheduled to be put on the queue). At the scheduled delivery time of 12:05, the broker puts the message on the head of the queue. However, since the ring queue has already reached its configured size, the scheduled messageA
is immediately removed.
4.12.2.3. Paged messages
Similar to scheduled messages and messages in delivery, paged messages do not count towards the ring queue size enforced by the broker, because messages are actually paged at the address level, not the queue level. A paged message is not technically on a queue, although it is reflected in a queue’s messageCount
value.
It is recommended that you do not use paging for addresses with ring queues. Instead, ensure that the entire address can fit into memory. Or, configure the address-full-policy
parameter to a value of DROP
, BLOCK
or FAIL
.
Additional resources
- The broker creates internal instances of ring queues when you configure retroactive addressing. To learn more, see Section 4.14, “Configuring Retroactive Addresses”.
4.13. Configuring a Prefix to Connect to a Specific Routing Type
Normally, if a message is received by an address that uses both anycast
and multicast
, one of the anycast
queues receive the message and all of the multicast
queues. However, clients can specify a special prefix when connecting to an address to specify whether to connect using anycast
or multicast
. The prefixes are custom values that are designated using the anycastPrefix
and multicastPrefix
parameters within the URL of an acceptor
.
Configuring an Anycast Prefix
-
In
BROKER_INSTANCE_DIR/etc/broker.xml
, add theanycastPrefix
to the URL of the desiredacceptor
. In the example below, theacceptor
is configured to useanycast://
for theanycastPrefix
. Client code can specifyanycast://foo/
if the client needs to send a message to only one of the anycast queues.
<configuration ...> <core ...> ... <acceptors> <!-- Acceptor for every supported protocol --> <acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP;anycastPrefix=anycast://</acceptor> </acceptors> ... </core> </configuration>
Configuring a Multicast Prefix
-
In
BROKER_INSTANCE_DIR/etc/broker.xml
, add theanycastPrefix
to the URL of the desiredacceptor
. In the example below, theacceptor
is configured to usemulticast://
for themulticastPrefix
. Client code can specifymulticast://foo/
if the client needs the message sent to only the multicast queues of the address.
<configuration ...> <core ...> ... <acceptors> <!-- Acceptor for every supported protocol --> <acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP;multicastPrefix=multicast://</acceptor> </acceptors> ... </core> </configuration>
4.14. Configuring Retroactive Addresses
Configuring an address as retroactive enables you to preserve messages sent to that address, including when there are no queues yet bound to the address. When queues are later created and bound to the address, the broker retroactively distributes messages to those queues. If an address is not configured as retroactive and does not yet have a queue bound to it, the broker discards messages sent to that address.
When you configure a retroactive address, the broker creates an internal instance of a type of queue known as a ring queue. A ring queue is a special type of queue that holds a specified, fixed number of messages. Once the queue has reached the specified size, the next message that arrives to the queue forces the oldest message out of the queue. When you configure a retroactive address, you indirectly specify the size of the internal ring queue. By default, the internal queue uses the multicast
routing type.
The internal ring queue used by a retroactive address is exposed via the management API. You can inspect metrics and perform other common management operations, such as emptying the queue. The ring queue also contributes to the overall memory usage of the address, which affects behavior such as message paging.
This procedure shows how to configure an address as retroactive.
Procedure
-
Open the
BROKER_INSTANCE_DIR/etc/broker.xml
configuration file. Specify a value for the
retroactive-message-count
parameter in theaddress-setting
element. The value you specify defines the number of messages you want the broker to preserve. For example:<configuration> <core> ... <address-settings> <address-setting match="orders"> <retroactive-message-count>100</retroactive-message-count> </address-setting> </address-settings> ... </core> </configuration>
NoteYou can update the value of
retroactive-message-count
while the broker is running, in either thebroker.xml
configuration file or the management API. However, if you reduce the value of this parameter, an additional step is required, because retroactive addresses are implemented via ring queues. A ring queue whosering-size
parameter is reduced does not automatically delete messages from the queue to achieve the newring-size
value. This behavior is a safeguard against unintended message loss. In this case, you need to use the management API to manually reduce the number of messages in the ring queue.
Additional resources
- For more information about ring queues, see Section 4.12, “Configuring Ring Queues”.
4.15. Protocol Managers and Addresses
A protocol manager maps protocol-specific concepts down to the AMQ Broker address model concepts: queues and routing types. For example, when a client sends a MQTT subscription packet with the addresses /house/room1/lights
and /house/room2/lights
, the MQTT protocol manager understands that the two addresses require multicast
semantics. The protocol manager therefore first looks to ensure that multicast
is enabled for both addresses. If not, it attempts to dynamically create them. If successful, the protocol manager then creates special subscription queues for each subscription requested by the client.
Each protocol behaves slightly differently. The table below describes what typically happens when subscribe frames to various types of queue
are requested.
If the queue is of this type… | The typical action for a protocol manager is to… |
---|---|
Durable Subscription Queue |
Look for the appropriate address and ensures that The special name allows the protocol manager to quickly identify the required client subscription queues should the client disconnect and reconnect at a later date. When the client unsubscribes the queue is deleted. |
Temporary Subscription Queue |
Look for the appropriate address and ensures that When the client disconnects the queue is deleted. |
Point-to-Point Queue |
Look for the appropriate address and ensures that If the queue is auto created, it is automatically deleted once there are no consumers and no messages in it. |
4.16. Disabling Advisory Messages
By default, AMQ creates advisory messages about addresses and queues when an OpenWire client is connected to the broker. Advisory messages are sent to internally managed addresses created by the broker. These addresses appear on the AMQ Console within the same display as user-deployed addresses and queues. Although they provide useful information, advisory messages can cause unwanted consequences when the broker manages a large number of destinations. For example, the messages might increase memory usage or strain connection resources. Also, the AMQ Console might become cluttered when attempting to display all of the addresses created to send advisory messages. To avoid these situations, use the supportAdvisory
and suppressInternalManagementObjects
parameters to manage the advisory messages behavior on the broker side.
-
supportAdvisory: Set this option to
true
to enable creation of advisory messages orfalse
to disable them. The default value istrue
. -
suppressInternalManagementObjects: Set this option to
true
to expose the advisory messages to the management service such as JMX registry and AMQ Console, orfalse
to not expose them. The default value istrue
.
Use these parameters by editing the BROKER_INSTANCE_DIR/etc/broker.xml
configuration file and configure the parameters on openwire acceptors by using URLs. For example:
<acceptor name="artemis">tcp://127.0.0.1:61616?protocols=CORE,AMQP,OPENWIRE;supportAdvisory=false;suppressInternalManagementObjects=false</acceptor>
4.17. Configuring Address Settings
AMQ Broker has several configurable options that control aspects of how and when a message is delivered, how many attempts should be made, and when the message expires. These configuration options all exist within the <address-setting>
configuration element. You can have AMQ Broker apply a single <address-setting>
to multiple destinations by using a wildcard syntax.
AMQ Broker Wildcard Syntax
AMQ Broker uses a specific syntax for representing wildcards in security settings, address settings, and when creating consumers.
- A wildcard expression contains words delimited by the character ‘.’.
- The special characters ‘#’ and ‘*’ also have special meaning and can take the place of a word.
- The character ‘#’ means 'match any sequence of zero or more words'. Use this at the end of your expression.
- The character ‘*’ means 'match a single word'. Use this anywhere within your expression.
Matching is not done character by character, but at each delimiter boundary. For example, an address-setting
looking to match queues using my
in their name would not match with a queue named myqueue
.
When more than one address-setting
matches a queue, the broker will overlay configurations, using the configuration of the least specific match as the baseline. Literal expressions are more specific than wildcards, and *
is more specific than #
. For example, both my.queue
and my.*
match the queue my.queue
. In this case, the broker first applies the configuration found under my.*
, since a wildcard expression is less specific than a literal. Next, the broker overlays the configuration of the my.queue
address-setting
, which will overwrite any configuration shared with my.*
. Given the configuration below, the queue my.queue
would have max-delivery-attempts
set to 3
and last-value-queue
set to false
.
<address-setting match="my.*"> <max-delivery-attempts>3</max-delivery-attempts> <last-value-queue>true</last-value-queue> </address-setting> <address-setting match="my.queue"> <last-value-queue>false</last-value-queue> </address-setting>
The examples in the table below illustrate how wildcards are used to match a set of addresses.
Example | Description |
---|---|
# |
The default |
news.europe.# |
Matches |
news.* |
Matches |
news.*.sport |
Matches |
Configuring Wildcard Syntax
You can customize the syntax used for wildcard addresses by adding configuration to broker.xml
.
Procedure
-
Edit
broker.xml
by adding a<wildcard-addresses>
section to the configuration, as in the example below.
<configuration> <core> ... <wildcard-addresses> 1 <enabled>true</enabled> 2 <delimiter>,</delimiter> 3 <any-words>@</any-words> 4 <single-word>$</single-word> 5 </wildcard-addresses> ... </core> </configuration>
- 1
- Add
wildcard-addresses
beneath thecore
configuration element. - 2
- Set
enabled
totrue
to tell the broker to use your custom settings. - 3
- Provide a custom character to use as the
delimiter
instead of the default, which is.
. - 4
- The character provided as the value for
any-words
is used to mean 'match any sequence of zero or more words' and will replace the default#
. Use this character at the end of your expression. - 5
- The character provided as the value for
single-word
is used to mean 'match a single word' and will replaced the default*
. Use this character anywhere within your expression.
4.18. Creating and Deleting Queues and Addresses Automatically
You can configure AMQ Broker to automatically create addresses and queues, and to delete them after they are no longer in use. This saves you from having to pre-configure each address before a client can connect to it.
Automatic creation and deletion of queues and addresses is configured on a per address-setting
basis. The configuration is applied to any address or queue that is a match for the address-setting
. For more information about how to use wildcard syntax to match addresses and queues to an address-setting
see Configuring Address Settings.
Disabling the automatic creation of queues and addresses can cause problems and is not recommended. AMQ Broker must be able to auto-create addresses and queues by using the activemq.#
pattern. For an example see the example address setting.
The following table lists the configuration elements available when configuring an address-setting
to automatically create and delete its queues and addresses.
If you want the address-setting to… | Add this configuration… |
---|---|
Create addresses when a client sends a message to or attempts to consume a message from a queue mapped to an address that does not exist. |
|
Create a queue when a client sends a message to or attempts to consume a message from a queue. |
|
Delete an automatically created address when it no longer has any queues. |
|
Delete an automatically created queue when the queue has 0 consumers and 0 messages. |
|
Use a specific routing type if the client does not specify one. |
|
Procedure
Edit the BROKER_INSTANCE_DIR/etc/broker.xml
file and configure an address-setting
for automatic creation and deletion. The following example uses all of the configuration elements mentioned in the previous table.
<configuration ...> <core ...> ... <address-settings> <address-setting match="activemq.#"> 1 <auto-create-addresses>true</auto-create-addresses> 2 <auto-delete-addresses>true</auto-delete-addresses> 3 <auto-create-queues>true</auto-create-queues> 4 <auto-delete-queues>true</auto-delete-queues> 5 <default-address-routing-type>ANYCAST</default-address-routing-type> 6 </address-setting> </address-settings> ... </core> </configuration>
- 1
- The configuration included in this
address-setting
is applied to any address or queue that matches the wildcardactivemq.#
. For more information on using wildcard syntax see AMQ Broker Wildcard Syntax. - 2
- The broker creates an address that does not exist when a client requests it.
- 3
- An automatically created address is deleted when it no longer has any queues associated with it.
- 4
- The broker creates a queue that does not exist when a client requests it.
- 5
- An automatically created queue is deleted when it no longer has any consumers or messages.
- 6
- If the client does not specify a routing type when connecting, the broker uses
ANYCAST
when delivering messages to an address. The default value isMULTICAST
. See the introduction of this chapter for more information about routing types.
4.19. Moving Expired Messages to an Expiry Address
For a queue other than a last value queue, if you have only non-destructive consumers, the broker never deletes messages from the queue, causing the queue size to increase over time. To prevent this unconstrained growth in queue size, you can configure when messages expire and specify an address to which the broker moves expired messages.
4.19.1. Configuring Message Expiry
The following procedure shows how to configure message expiry.
Procedure
-
Open the
<broker-instance-dir>/etc/broker.xml
configuration file. In the
core
element, set themessage-expiry-scan-period
to specify how frequently the broker scans for expired messages.<configuration ...> <core ...> ... <message-expiry-scan-period>1000</message-expiry-scan-period> ...
Based on the preceding configuration, the broker scans queues for expired messages every 1000 milliseconds (that is, once every second).
In the
address-setting
element for a matching address or set of addresses, specify an expiry address. Also, set a message expiration time. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="stocks"> ... <expiry-address>ExpiryAddress</expiry-address> <expiry-delay>10</expiry-delay> ... </address-setting> ... <address-settings> <configuration ...>
expiry-address
-
Expiry address for the matching address or addresses. In the preceding example, the broker sends expired messages for the
stocks
address to an expiry address calledExpiryAddress
. expiry-delay
Expiration time, in milliseconds, that the broker applies to messages that are using the default expiration time. By default, messages have an expiration time of
0
, meaning that they don’t expire. For messages with an expiration time greater than the default,expiry-delay
has no effect.For example, suppose you set
expiry-delay
on an address to10
, as shown in the preceding example. If a message with the default expiration time of0
arrives to a queue at this address, then the broker changes the expiration time of the message from0
to10
. However, if another message that is using an expiration time of20
arrives, then its expiration time is unchanged. If you set expiry-delay to-1
, this feature is disabled. By default,expiry-delay
is set to-1
.
Alternatively, instead of specifying a value for
expiry-delay
, you can specify minimum and maximum expiry delay values. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="stocks"> ... <expiry-address>ExpiryAddress</expiry-address> <min-expiry-delay>10</min-expiry-delay> <max-expiry-delay>100</max-expiry-delay> ... </address-setting> ... <address-settings> <configuration ...>
min-expiry-delay
- Minimum expiration time, in milliseconds, that the broker applies to messages.
max-expiry-delay
Maximum expiration time, in milliseconds, that the broker applies to messages.
The broker applies the values of
min-expiry-delay
andmax-expiry-delay
as follows:-
For a message with the default expiration time of
0
, the broker sets the expiration time to the specified value ofmax-expiry-delay
. If you have not specified a value formax-expiry-delay
, the broker sets the expiration time to the specified value ofmin-expiry-delay
. If you have not specified a value formin-expiry-delay
, the broker does not change the expiration time of the message. -
For a message with an expiration time above the value of
max-expiry-delay
, the broker sets the expiration time to the specified value ofmax-expiry-delay
. -
For a message with an expiration time below the value of
min-expiry-delay
, the broker sets the expiration time to the specified value ofmin-expiry-delay
. -
For a message with an expiration between the values of
min-expiry-delay
andmax-expiry-delay
, the broker does not change the expiration time of the message. -
If you specify a value for
expiry-delay
(that is, other than the default value of-1
), this overrides any values that you specify formin-expiry-delay
andmax-expiry-delay
. -
The default value for both
min-expiry-delay
andmax-expiry-delay
is-1
(that is, disabled).
-
For a message with the default expiration time of
In the
addresses
element of your configuration file, configure the address previously specified forexpiry-address
. Define a queue at this address. For example:<addresses> ... <address name="ExpiryAddress"> <anycast> <queue name="ExpiryQueue"/> </anycast> </address> ... </addresses>
The preceding example configuration associates an expiry queue,
ExpiryQueue
, with the expiry address,ExpiryAddress
.
4.19.2. Creating Expiry Resources Automatically
A common use case is to segregate expired messages according to their original addresses. For example, you might choose to route expired messages from an address called stocks
to an expiry queue called EXP.stocks
. Likewise, you might route expired messages from an address called orders
to an expiry queue called EXP.orders
.
This type of routing pattern makes it easy to track, inspect, and administer expired messages. However, a pattern such as this is difficult to implement in an environment that uses mainly automatically-created addresses and queues. In this type of environment, an administrator does not want the extra effort required to manually create addresses and queues to hold expired messages.
As a solution, you can configure the broker to automatically create resources (that is, addressees and queues) to handle expired messages for a given address or set of addresses. The following procedure shows an example.
Prerequisites
- You have already configured an expiry address for a given address or set of addresses. For more information, see Section 4.19.1, “Configuring Message Expiry”.
Procedure
-
Open the
<broker-instance-dir>/etc/broker.xml
configuration file. Locate the
<address-setting>
element that you previously added to the configuration file to define an expiry address for a matching address or set of addresses. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="stocks"> ... <expiry-address>ExpiryAddress</expiry-address> ... </address-setting> ... <address-settings> <configuration ...>
In the
<address-setting>
element, add configuration items that instruct the broker to automatically create expiry resources (that is, addresses and queues) and how to name these resources. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="stocks"> ... <expiry-address>ExpiryAddress</expiry-address> <auto-create-expiry-resources>true</auto-create-expiry-resources> <expiry-queue-prefix>EXP.</expiry-queue-prefix> <expiry-queue-suffix></expiry-queue-suffix> ... </address-setting> ... <address-settings> <configuration ...>
auto-create-expiry-resources
Specifies whether the broker automatically creates an expiry address and queue to receive expired messages. The default value is
false
.If the parameter value is set to
true
, the broker automatically creates an<address>
element that defines an expiry address and an associated expiry queue. The name value of the automatically-created<address>
element matches the name value specified for<expiry-address>
.The automatically-created expiry queue has the
multicast
routing type. By default, the broker names the expiry queue to match the address to which expired messages were originally sent, for example,stocks
.The broker also defines a filter for the expiry queue that uses the
_AMQ_ORIG_ADDRESS
property. This filter ensures that the expiry queue receives only messages sent to the corresponding original address.expiry-queue-prefix
Prefix that the broker applies to the name of the automatically-created expiry queue. The default value is
EXP.
When you define a prefix value or keep the default value, the name of the expiry queue is a concatenation of the prefix and the original address, for example,
EXP.stocks
.expiry-queue-suffix
- Suffix that the broker applies to the name of an automatically-created expiry queue. The default value is not defined (that is, the broker applies no suffix).
You can directly access the expiry queue using either the queue name by itself (for example, when using the AMQ Broker Core Protocol JMS client) or using the fully qualified queue name (for example, when using another JMS client).
Because the expiry address and queue are automatically created, any address settings related to deletion of automatically-created addresses and queues also apply to these expiry resources.
Additional resources
- For more information about address settings used to configure automatic deletion of automatically-created addresses and queues, see Section 4.18, “Creating and Deleting Queues and Addresses Automatically”.
4.20. Moving Undelivered Messages to a Dead Letter Address
If delivery of a message to a client is unsuccessful, you might not want the broker to make ongoing attempts to deliver the message. To prevent infinite delivery attempts, you can define a dead letter address and one or more asscociated dead letter queues. After a specified number of delivery attempts, the broker removes an undelivered message from its original queue and sends the message to the configured dead letter address. A system administrator can later consume undelivered messages from a dead letter queue to inspect the messages.
If you do not configure a dead letter address for a given queue, the broker permanently removes undelivered messages from the queue after the specified number of delivery attempts.
Undelivered messages that are consumed from a dead letter queue have the following properties:
_AMQ_ORIG_ADDRESS
- String property that specifies the original address of the message
_AMQ_ORIG_QUEUE
- String property that specifies the original queue of the message
4.20.1. Configuring a Dead Letter Address
The following procedure shows how to configure a dead letter address and an associated dead letter queue.
Procedure
-
Open the
<broker-instance-dir>/etc/broker.xml
configuration file. In an
<address-setting>
element that matches your queue name(s), set values for the dead letter address name and the maximum number of delivery attempts. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="exampleQueue"> <dead-letter-address>DLA</dead-letter-address> <max-delivery-attempts>3</max-delivery-attempts> </address-setting> ... <address-settings> <configuration ...>
dead-letter-address
Name of the dead letter address. In this example, the broker moves undelivered messages from the queue exampleQueue to the dead letter address, DLA.
NoteYou can specify a wildcard expression for the
match
attribute of the<address-setting>
element. Using a wildcard expression is useful if you want to associate the dead letter settings configured in the<address-setting>
element with a matching set of addresses.max-delivery-attempts
-
Maximum number of delivery attempts made by the broker before it moves an undelivered message to the configured dead letter address. In this example, the broker moves undelivered messages to the dead letter address after three unsuccessful delivery attempts. The default value is
10
. If you want the broker to make an infinite number of redelivery attempts, specify a value of-1
.
In the
addresses
section, add anaddress
element for the dead letter address, DLA. To associate a dead letter queue with the dead letter address, specify a name value forqueue
. For example:<configuration ...> <core ...> ... <addresses> <address name="DLA"> <anycast> <queue name="DLQ" /> </anycast> </address> ... </addresses> </core> </configuration>
In the preceding configuration, you associate a dead letter queue named DLQ with the dead letter address, DLA.
Additional resources
- For more information about using wildcards in address settings, see AMQ Broker Wildcard Syntax.
4.20.2. Creating Dead Letter Queues Automatically
A common use case is to segregate undelivered messages according to their original addresses. For example, you might choose to route undelivered messages from an address called stocks
to a dead letter queue called DLA.stocks
that has an associated dead letter queue called DLQ.stocks
. Likewise, you might route undelivered messages from an address called orders
to a dead letter address called DLA.orders
.
This type of routing pattern makes it easy to track, inspect, and administrate undelivered messages. However, a pattern such as this is difficult to implement in an environment that uses mainly automatically-created addresses and queues. It is likely that a system administrator for this type of environment does not want the additional effort required to manually create addresses and queues to hold undelivered messages.
As a solution, you can configure the broker to automatically create addressees and queues to handle undelivered messages, as shown in the procedure that follows.
Prerequisites
- You have already configured a dead letter address for a queue or set of queues. For more information, see Section 4.20.1, “Configuring a Dead Letter Address”.
Procedure
-
Open the
<broker-instance-dir>/etc/broker.xml
configuration file. Locate the
<address-setting>
element that you previously added to define a dead letter address for a matching queue or set of queues. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="exampleQueue"> <dead-letter-address>DLA</dead-letter-address> <max-delivery-attempts>3</max-delivery-attempts> </address-setting> ... <address-settings> <configuration ...>
In the
<address-setting>
element, add configuration items that instruct the broker to automatically create dead letter resources (that is, addresses and queues) and how to name these resources. For example:<configuration ...> <core ...> ... <address-settings> ... <address-setting match="exampleQueue"> <dead-letter-address>DLA</dead-letter-address> <max-delivery-attempts>3</max-delivery-attempts> <auto-create-dead-letter-resources>true</auto-create-dead-letter-resources> <dead-letter-queue-prefix>DLQ.</dead-letter-queue-prefix> <dead-letter-queue-suffix></dead-letter-queue-suffix> </address-setting> ... <address-settings> <configuration ...>
auto-create-dead-letter-resources
Specifies whether the broker automatically creates a dead letter address and queue to receive undelivered messages. The default value is
false
.If
auto-create-dead-letter-resources
is set totrue
, the broker automatically creates an<address>
element that defines a dead letter address and an associated dead letter queue. The name of the automatically-created<address>
element matches the name value that you specify for<dead-letter-address>
.The dead letter queue that the broker defines in the automatically-created
<address>
element has themulticast
routing type . By default, the broker names the dead letter queue to match the original address of the undelivered message, for example,stocks
.The broker also defines a filter for the dead letter queue that uses the
_AMQ_ORIG_ADDRESS
property. This filter ensures that the dead letter queue receives only messages sent to the corresponding original address.dead-letter-queue-prefix
Prefix that the broker applies to the name of an automatically-created dead letter queue. The default value is
DLQ.
When you define a prefix value or keep the default value, the name of the dead letter queue is a concatenation of the prefix and the original address, for example,
DLQ.stocks
.dead-letter-queue-suffix
- Suffix that the broker applies to an automatically-created dead letter queue. The default value is not defined (that is, the broker applies no suffix).
4.21. Annotations and Properties on Expired or Undelivered AMQP Messages
Before the broker moves an expired or undelivered AMQP message to an expiry or dead letter queue that you have configured, the broker applies annotations and properties to the message. A client can create a filter based on these properties or annotations, to select particular messages to consume from the expiry or dead letter queue.
The properties that the broker applies are internal properties These properties are are not exposed to clients for regular use, but can be specified by a client in a filter.
The following table shows the annotations and internal properties that the broker applies to expired or undelivered AMQP messages.
Annotation name | Internal property name | Description |
---|---|---|
x-opt-ORIG-MESSAGE-ID | _AMQ_ORIG_MESSAGE_ID | Original message ID, before the message was moved to an expiry or dead letter queue. |
x-opt-ACTUAL-EXPIRY | _AMQ_ACTUAL_EXPIRY | Message expiry time, specified as the number of milliseconds since the last epoch started. |
x-opt-ORIG-QUEUE | _AMQ_ORIG_QUEUE | Original queue name of the expired or undelivered message. |
x-opt-ORIG-ADDRESS | _AMQ_ORIG_ADDRESS | Original address name of the expired or undelivered message. |
Additional resources
- For an example of configuring an AMQP client to filter AMQP messages based on annotations, see Section 16.3, “Filtering AMQP Messages Based on Properties on Annotations”.