AMQP 1.0
This component speaks AMQP 1.0. It is verified against Apache ActiveMQ Artemis and Solace PubSub+.
AMQP 1.0, not AMQP 0-9-1
AMQP 1.0 and AMQP 0-9-1 are different protocols. For RabbitMQ, use the RabbitMQ component instead, which speaks AMQP 0-9-1.Component format
To set up AMQP pub/sub, create a component of type pubsub.amqp. See the pub/sub broker component file to learn how ConsumerID is automatically generated. Read the How-to: Publish and Subscribe guide on how to create and apply a pub/sub configuration.
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: amqp-pubsub
spec:
type: pubsub.amqp
version: v1
metadata:
- name: url
value: 'amqp://localhost:5672'
- name: username
value: 'default'
- name: password
value: 'default'
Warning
The above example uses secrets as plain strings. It is recommended to use a secret store for the secrets as described here.Spec metadata fields
| Field | Required | Details | Example |
|---|---|---|---|
| url | Y | Address of the AMQP broker. Can be secretKeyRef to use a secret reference.Use the amqp:// URI scheme for non-TLS communication.Use the amqps:// URI scheme for TLS communication. | "amqp://host.domain[:port]" |
| username | N | The username to connect to the broker. Required unless anonymous is true. | default |
| password | N | The password to connect to the broker. Required unless anonymous is true. | default |
| anonymous | N | Skip SASL username/password authentication (SASL ANONYMOUS). Combine with clientCert and clientKey over amqps:// to authenticate with the client certificate only (mutual TLS). Must be allowed on the broker. | true |
| caCert | N | Certificate Authority (CA) certificate in PEM format for verifying server TLS certificates. Only needed when the broker certificate is not signed by a publicly trusted CA. Requires the amqps:// scheme. | "-----BEGIN CERTIFICATE-----\n<base64-encoded DER>\n-----END CERTIFICATE-----" |
| clientCert | N | TLS client certificate in PEM format, for mutual TLS. Must be used with clientKey, and requires the amqps:// scheme. | "-----BEGIN CERTIFICATE-----\n<base64-encoded DER>\n-----END CERTIFICATE-----" |
| clientKey | N | TLS client key in PEM format, for mutual TLS. Must be used with clientCert, and requires the amqps:// scheme. Can be secretKeyRef to use a secret reference. | "-----BEGIN RSA PRIVATE KEY-----\n<base64-encoded PKCS8>\n-----END RSA PRIVATE KEY-----" |
| topicAddressPrefix | N | Prefix prepended to the AMQP address of a topic, used for a bare topic name and for topics named topic:<name>. Defaults to no prefix, which addresses the topic by name. See Addressing topics and queues. | multicast:// |
| queueAddressPrefix | N | Prefix prepended to the AMQP address of a queue, used for topics named queue:<name>. Defaults to no prefix, which addresses the queue by name. See Addressing topics and queues. | anycast:// |
| containerID | N | AMQP container ID of the connections that carry named subscriptions. The broker identifies a named subscription by the container ID and the subscription name. Defaults to the consumer ID that Dapr gives every pub/sub component: the app ID, or consumerID if the component sets it (see the pub/sub broker component file). So by default every replica of the app shares it. Do not set containerID or consumerID to a per-replica value, such as the {podName} or {uuid} markers: each replica then gets a subscription of its own and a copy of every message. See Named, durable and shared subscriptions. | orders-service |
| durableMessages | N | Mark every published message as durable, so that the broker keeps it across a broker restart. AMQP 1.0 messages are not durable unless explicitly specified. Defaults to false. | true |
| applicationPropertiesFromMetadata | N | Copy the metadata of each publish request into the message, so that a broker-side filter can match on it. Defaults to false. See Filter on message properties. | true |
| backOffPolicy | N | Retry policy used between attempts to re-open a subscription after the broker connection drops. Either constant or exponential. Defaults to constant. | "constant" |
| backOffDuration | N | Delay between attempts to re-open a subscription, when backOffPolicy is constant. Defaults to 5s. The component retries for as long as the subscription exists, so this sets the pace, not a limit. | 1s |
| backOffInitialInterval | N | First delay between attempts, when backOffPolicy is exponential. Defaults to 500ms. | 100ms |
| backOffMaxInterval | N | Longest delay between attempts, when backOffPolicy is exponential. Defaults to 60s. | 30s |
Communication using TLS
To configure communication using TLS:
- Ensure that the broker is configured to support certificates. For mutual TLS on ActiveMQ Artemis, set
sslEnabled=true;needClientAuth=trueon the acceptor so clients without a trusted certificate are rejected. - Provide the
caCert,clientCert, andclientKeymetadata in the component configuration.
For example:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: amqp-pubsub
spec:
type: pubsub.amqp
version: v1
metadata:
- name: url
value: "amqps://host.domain[:port]"
- name: username
value: 'default'
- name: password
value: 'default'
- name: caCert
value: ${{ myLoadedCACert }}
- name: clientCert
value: ${{ myLoadedClientCert }}
- name: clientKey
secretKeyRef:
name: myAmqpClientKey
key: myAmqpClientKey
auth:
secretStore: <SECRET_STORE_NAME>
While the
caCertandclientCertvalues may not be secrets, they can be referenced from a Dapr secret store as well for convenience.
To authenticate with the client certificate only (mutual TLS), set anonymous to true and omit username and password:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: amqp-pubsub
spec:
type: pubsub.amqp
version: v1
metadata:
- name: url
value: "amqps://host.domain[:port]"
- name: anonymous
value: "true"
- name: caCert
value: ${{ myLoadedCACert }}
- name: clientCert
value: ${{ myLoadedClientCert }}
- name: clientKey
secretKeyRef:
name: myAmqpClientKey
key: myAmqpClientKey
auth:
secretStore: <SECRET_STORE_NAME>
Before Dapr 1.19, anonymous was ignored over amqps:// and SASL PLAIN was always used.
Addressing topics and queues
The component turns a Dapr topic name into an AMQP address. topicAddressPrefix and queueAddressPrefix control that translation, and both default to no prefix. So out of the box the AMQP address is the Dapr topic name, unchanged:
| Dapr topic name | AMQP address, with the default prefixes |
|---|---|
orders | orders |
topic:orders | orders |
queue:orders | orders |
`queue:` does nothing until the prefixes are configured
A Dapr topic name may carry a queue: or topic: scheme. The scheme selects which of the two prefixes is applied — it does not select a routing type by itself.
With no prefixes configured, queue:orders and orders resolve to the same address, so the scheme has no effect and the routing type is whatever the broker resolves for that address.
To make queue: select a queue, set both prefixes to the values your broker uses. See Brokers that namespace destinations.
A topic name that already begins with one of the configured prefixes is used as the AMQP address unchanged.
Brokers that namespace destinations
Some brokers select the routing type from a prefix on the address. Set topicAddressPrefix and queueAddressPrefix to the prefixes that broker uses, and the queue: and topic: schemes then select the routing type.
Apache ActiveMQ Artemis
An Artemis acceptor takes anycastPrefix and multicastPrefix settings. If the acceptor is configured with anycastPrefix=anycast://;multicastPrefix=multicast://, configure the component to match. Use whatever prefixes your acceptor defines; queue:// and topic:// are also common:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: artemis
spec:
type: pubsub.amqp
version: v1
metadata:
- name: url
value: 'amqp://localhost:5672'
- name: username
value: 'artemis'
- name: password
value: 'artemis'
- name: topicAddressPrefix
value: 'multicast://'
- name: queueAddressPrefix
value: 'anycast://'
A Dapr topic named orders is then addressed as multicast://orders, and queue:orders as anycast://orders.
Without these prefixes, the routing type comes from the broker instead, through the default-address-routing-type of the matching address setting.
Consume from a queue that the broker manages
Artemis accepts a fully qualified queue name, <address>::<queue>. Subscribe to it to consume from a queue defined in broker.xml, with the durability and filter configured there:
apiVersion: dapr.io/v2alpha1
kind: Subscription
metadata:
name: billing
spec:
pubsubname: artemis
topic: "orders::billing"
routes:
default: /billing
Every replica of the app consumes from the same queue, and closing the subscription never deletes the queue. Create the queue before the app starts: a queue that Artemis creates automatically is subject to auto-delete-queues.
This example uses the default address prefixes, which are empty. If you set topicAddressPrefix, the component adds it in front of the topic name, so the link opens on <prefix>orders::billing.
Solace PubSub+
Solace addresses topics as topic://<name> and queues as queue://<name>:
- name: topicAddressPrefix
value: 'topic://'
- name: queueAddressPrefix
value: 'queue://'
Interoperating with non-Dapr clients
A prefix namespaces the address. A Dapr publisher usingtopic://orders and a non-Dapr client subscribing to orders are on two different addresses and never exchange messages. Make sure every client on a destination agrees on the address.Named, durable and shared subscriptions
Dapr 1.19 or later
ThesubscriptionName, durable, shared and selector subscription keys, and the containerID, durableMessages and applicationPropertiesFromMetadata component keys, need Dapr 1.19 or later.By default, each subscription attaches with the broker defaults. On a multicast address that is usually a temporary subscription: each replica of the app gets its own copy of every message, and messages published while the app is down are lost.
A subscription can set the keys below in its own metadata. They use standard AMQP 1.0 mechanisms, so they apply to any broker that supports durable subscriptions, the shared capability and the JMS selector filter. They are verified with ActiveMQ Artemis. See Named subscriptions on ActiveMQ Artemis for how Artemis applies them, and Other brokers.
| Field | Details | Example |
|---|---|---|
| subscriptionName | Name of the subscription, sent as the AMQP link name. Together with containerID, it identifies the subscription on the broker. Required for durable and shared. Must not contain |, and must be unique among the subscriptions of one component. Not allowed on a queue (queue:<name>), which has no subscription to name. | billing |
| durable | Ask the broker to keep the subscription, and the messages it holds, while no consumer is attached. The component sends a durable source that never expires. Defaults to false. | true |
| shared | Ask for a shared subscription, with the shared source capability. Every replica that uses the same subscriptionName then consumes from one subscription, so that each message reaches one replica. Defaults to false. | true |
| selector | A JMS selector, sent as the apache.org:selector-filter:string filter, that the broker applies to the subscription. Messages that do not match never enter it. If the broker attaches without the filter, the subscription fails. Can be set without subscriptionName. | eventType = 'invoice' |
For example:
apiVersion: dapr.io/v2alpha1
kind: Subscription
metadata:
name: billing
spec:
pubsubname: artemis
topic: orders
routes:
default: /billing
metadata:
subscriptionName: billing
durable: "true"
shared: "true"
selector: "eventType = 'invoice'"
Every replica of the app consumes from one durable subscription named billing, which holds only the messages that match the selector.
Keep these points in mind, on any broker:
- Replicas. Set
sharedwhen the app has more than one replica. A broker can let only one consumer attach to a durable subscription that is not shared. - Several subscriptions on one topic. Dapr keeps one declarative or programmatic subscription per pub/sub component and topic. To hold several named subscriptions on one topic, define one component per subscription, as in the example below, or use streaming subscriptions.
- Changing a selector. A broker can treat a changed selector as a new subscription, and drop the messages the old one held. To change a selector, use a new
subscriptionName. - Removing a subscription. Dapr never deletes a durable subscription, even when the subscription is removed from the app. Delete it on the broker.
- Broker restarts. A durable subscription keeps durable messages only. Set
durableMessageson the publishing component, or publish durable messages from other clients. JMS clients publish durable messages by default. - Permissions. The broker user needs permission to create durable subscriptions and to consume from them. With
anonymous: "true"there is no user name: give the permissions to the role that the broker maps the connection to, for example the role of the client certificate. - Connections. Each named subscription uses a connection of its own, so that the container ID stays fixed and stopping the subscription never deletes it.
Several subscriptions on one topic
Dapr maps one declarative or programmatic subscription per pub/sub component and topic. Thus, two named subscriptions on the topic orders, each with its own selector, require two Dapr components on the same broker:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: billing
spec:
type: pubsub.amqp
version: v1
metadata:
- name: url
value: 'amqp://localhost:5672'
- name: username
value: 'artemis'
- name: password
value: 'artemis'
---
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: audit
spec:
type: pubsub.amqp
version: v1
metadata:
- name: url
value: 'amqp://localhost:5672'
- name: username
value: 'artemis'
- name: password
value: 'artemis'
Each component is then referenced by a single subscription:
apiVersion: dapr.io/v2alpha1
kind: Subscription
metadata:
name: billing
spec:
pubsubname: billing
topic: orders
routes:
default: /billing
metadata:
subscriptionName: billing
durable: "true"
shared: "true"
selector: "eventType = 'invoice'"
---
apiVersion: dapr.io/v2alpha1
kind: Subscription
metadata:
name: audit
spec:
pubsubname: audit
topic: orders
routes:
default: /audit
metadata:
subscriptionName: audit
durable: "true"
shared: "true"
selector: "eventType = 'login'"
Both components use the same container ID, the app ID by default, and the subscription names keep the two subscriptions apart.
Named subscriptions on ActiveMQ Artemis
On ActiveMQ Artemis, the keys behave as follows:
- Queue names. Artemis names the queue of a named subscription
<containerID>.<subscriptionName>. For example, with the app IDorders-service, thebillingsubscription above is the durable queueorders-service.billingon the addressorders, with the selector as its filter. - Without the keys. Each subscription gets a temporary queue with a generated name, which Artemis removes when the subscription detaches.
- Replicas. A durable queue that is not shared accepts one consumer. Artemis refuses the others.
- Changing a selector. Artemis compares the selector each time a consumer attaches. If the selector changed and no consumer is attached, Artemis recreates the queue and drops the messages it held. If consumers are attached, Artemis refuses the new consumer.
- Removing a subscription. Delete the queue, for example from the Artemis console.
- Selectors. A selector reads application properties by name, the AMQP subject as
JMSType, and header fields such asAMQPriorityandAMQDurable. Artemis does not translate JMS header names such asJMSPriorityin these selectors. Application properties that Dapr copies are strings, so to compare one with a number, prefix the selector withconvert_string_expressions:, for exampleconvert_string_expressions:priority > 5. - Permissions. The role needs the
createDurableQueueandconsumepermissions on the address.
To consume from a queue that Artemis manages instead, see Consume from a queue that the broker manages.
Other brokers
These keys are not verified with other brokers, Solace PubSub+ included. A broker that does not support the shared capability can refuse a second replica or give it a copy of every message. If a broker ignores the selector filter, the component fails the subscription, because the broker does not return the filter.
Filter on message properties
A broker-side filter, such as a selector, matches on message properties. By default, a message that Dapr publishes carries no application properties. Set applicationPropertiesFromMetadata to true on the publishing component to copy the metadata of each publish request into the message:
- The
subjectkey sets the AMQP subject. - Every other key becomes an application property with a string value.
ttlInSeconds,rawPayloadandcloudevent.*keys are not copied.
These are standard AMQP 1.0 message properties, so any broker or client can read them. The selector syntax depends on the broker. For ActiveMQ Artemis, see Named subscriptions on ActiveMQ Artemis.
The mapping works in one direction. The component does not pass the application properties of a received message to the app.
For example, this publish request reaches the billing subscription above:
curl -X POST "http://localhost:3500/v1.0/publish/artemis/orders?metadata.eventType=invoice" \
-H "Content-Type: application/json" \
-d '{"orderId": "100"}'
When a subscriber returns an error
A message whose handler returns an error is returned to the broker as modified
with delivery-failed. The broker redelivers it and counts the attempt, so the
broker’s own redelivery-delay and max-delivery-attempts settings apply and a
message that always fails eventually reaches the dead-letter address.
Redelivery pacing and the attempt limit are broker settings, not component
settings. On ActiveMQ Artemis they live in address-settings; make sure a dead-letter address and max-delivery-attempts are configured there.
Migrating from pubsub.solace.amqp
Compatibility name
pubsub.solace.amqp is the earlier name of this component. It stays registered, and existing components of that type keep working with their topic:// and queue:// defaults. Use pubsub.amqp for new components.pubsub.amqp applies no address prefix by default, where pubsub.solace.amqp applies the Solace convention. To migrate a Solace component without changing the addresses it uses, change the type and set both prefixes explicitly:
spec:
type: pubsub.amqp # was pubsub.solace.amqp
version: v1
metadata:
- name: topicAddressPrefix
value: 'topic://'
- name: queueAddressPrefix
value: 'queue://'
Everything else in the component stays the same.
Create a broker
Run an Artemis broker locally using Docker:
docker run -d -p 5672:5672 -p 8161:8161 --env ARTEMIS_USER=artemis --env ARTEMIS_PASSWORD=artemis --name artemis apache/activemq-artemis:latest
The AMQP acceptor listens on amqp://localhost:5672, and the web console on http://localhost:8161.
Run a Solace broker locally using Docker:
docker run -d -p 8080:8080 -p 55554:55555 -p 8008:8008 -p 1883:1883 -p 8000:8000 -p 5672:5672 -p 9000:9000 -p 2222:2222 --shm-size=2g --env username_admin_globalaccesslevel=admin --env username_admin_password=admin --name=solace solace/solace-pubsub-standard
You can then interact with the server using the client port: amqp://localhost:5672
You can also sign up for a free SaaS broker on Solace Cloud.
Related links
- Basic schema for a Dapr component
- Read this guide for instructions on configuring pub/sub components
- Pub/sub building block