The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Reactive Messaging RabbitMQ Connector Reference Documentation

This guide is the companion from the Getting Started with RabbitMQ. It explains in more details the configuration and usage of the RabbitMQ connector for reactive messaging.

This documentation does not cover all the details of the connector. Refer to the SmallRye Reactive Messaging website for further details.

The RabbitMQ connector allows Quarkus applications to send and receive messages using the AMQP 0.9.1 protocol. More details about the protocol can be found in the AMQP 0.9.1 specification.

The RabbitMQ connector supports AMQP 0-9-1, which is very different from the AMQP 1.0 protocol used by the AMQP 1.0 connector. You can use the AMQP 1.0 connector with RabbitMQ as described in the AMQP 1.0 connector reference, albeit with reduced functionality.

This technology is considered preview.

In preview, backward compatibility and presence in the ecosystem is not guaranteed. Specific improvements might require changing configuration or APIs, and plans to become stable are under way. Feedback is welcome on our mailing list or as issues in our GitHub issue tracker.

For a full list of possible statuses, check our FAQ entry.

RabbitMQ connector extension

To use the connector, you need to add the quarkus-messaging-rabbitmq extension.

Puede añadir la extensión a su proyecto utilizando:

> ./mvnw quarkus:add-extensions -Dextensions="quarkus-messaging-rabbitmq"

O simplemente añada la siguiente dependencia a su proyecto:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-messaging-rabbitmq</artifactId>
</dependency>

Once added to your project, you can map channels to RabbitMQ exchanges or queues by configuring the connector attribute:

# Inbound
mp.messaging.incoming.[channel-name].connector=smallrye-rabbitmq

# Outbound
mp.messaging.outgoing.[channel-name].connector=smallrye-rabbitmq

outgoing channels are mapped to RabbitMQ exchanges and incoming channels are mapped to RabbitMQ queues as required by the broker.

Configuring the RabbitMQ Broker access

The RabbitMQ connector connects to RabbitMQ brokers. To configure the location and credentials of the broker, add the following properties in the application.properties:

rabbitmq-host=amqp (1)
rabbitmq-port=5672 (2)
rabbitmq-username=my-username (3)
rabbitmq-password=my-password (4)

mp.messaging.incoming.prices.connector=smallrye-rabbitmq (5)
1 Configures the broker host name. You can do it per channel (using the host attribute) or globally using rabbitmq-host
2 Configures the broker port. You can do it per channel (using the port attribute) or globally using rabbitmq-port. The default is 5672.
3 Configures the broker username if required. You can do it per channel (using the username attribute) or globally using rabbitmq-username.
4 Configures the broker password if required. You can do it per channel (using the password attribute) or globally using rabbitmq-password.
5 Instructs the prices channel to be managed by the RabbitMQ connector

In dev mode and when running tests, Dev Services for RabbitMQ automatically starts a RabbitMQ broker.

Receiving RabbitMQ messages

Let’s imagine your application receives Message<Double>. You can consume the payload directly:

package inbound;

import org.eclipse.microprofile.reactive.messaging.Incoming;

import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class RabbitMQPriceConsumer {

    @Incoming("prices")
    public void consume(double price) {
        // process your price.
    }

}

O bien, puede recuperar el Message<Double>:

package inbound;

import org.eclipse.microprofile.reactive.messaging.Incoming;
import org.eclipse.microprofile.reactive.messaging.Message;

import jakarta.enterprise.context.ApplicationScoped;
import java.util.concurrent.CompletionStage;

@ApplicationScoped
public class RabbitMQPriceMessageConsumer {

    @Incoming("prices")
    public CompletionStage<Void> consume(Message<Double> price) {
        // process your price.

        // Acknowledge the incoming message, marking the RabbitMQ message as `accepted`.
        return price.ack();
    }

}

Metadatos de entrada

Messages coming from RabbitMQ contain an instance of IncomingRabbitMQMetadata in the metadata.

Optional<IncomingRabbitMQMetadata> metadata = incoming.getMetadata(IncomingRabbitMQMetadata.class);
metadata.ifPresent(meta -> {
    final Optional<String> contentEncoding = meta.getContentEncoding();
    final Optional<String> contentType = meta.getContentType();
    final Optional<String> correlationId = meta.getCorrelationId();
    final Optional<ZonedDateTime> creationTime = meta.getCreationTime(ZoneId.systemDefault());
    final Optional<Integer> priority = meta.getPriority();
    final Optional<String> replyTo = meta.getReplyTo();
    final Optional<String> userId = meta.getUserId();

    // Access a single String-valued header
    final Optional<String> stringHeader = meta.getHeader("my-header", String.class);

    // Access all headers
    final Map<String,Object> headers = meta.getHeaders();
    // ...
});

Deserialización

The connector converts incoming RabbitMQ Messages into Reactive Messaging Message<T> instances. The payload type T depends on the value of the RabbitMQ received message Envelope content_type and content_encoding properties.

content_encoding content_type T

Value present

n/a

byte[]

No value

text/plain

String

No value

application/json

a JSON element which can be a JsonArray, JsonObject, String, …​etc if the buffer contains an array, object, string, …​etc

No value

Anything else

byte[]

If you send objects with this RabbitMQ connector (outbound connector), they are encoded as JSON and sent with content_type set to application/json. You can receive this payload using (Vert.x) JSON Objects, and then map it to the object class you want:

@ApplicationScoped
public static class Generator {

    @Outgoing("to-rabbitmq")
    public Multi<Price> prices() { (1)
        AtomicInteger count = new AtomicInteger();
        return Multi.createFrom().ticks().every(Duration.ofMillis(1000))
                .map(l -> new Price().setPrice(count.incrementAndGet()))
                .onOverflow().drop();
    }

}

@ApplicationScoped
public static class Consumer {

    List<Price> prices = new CopyOnWriteArrayList<>();

    @Incoming("from-rabbitmq")
    public void consume(JsonObject p) { (2)
        Price price = p.mapTo(Price.class); (3)
        prices.add(price);
    }

    public List<Price> list() {
        return prices;
    }
}
1 Las instancias de Price son codificadas automáticamente en JSON por el conector
2 Puede recibirlo mediante un JsonObject
3 A continuación, puede reconstruir la instancia utilizando el método mapTo
El método mapTo utiliza el mapeador Quarkus Jackson. Consulta esta guía para saber más sobre la configuración del mapeador.

Agradecimiento

When a Reactive Messaging Message associated with a RabbitMQ Message is acknowledged, it informs the broker that the message has been accepted.

Whether you need to explicitly acknowledge the message depends on the auto-acknowledgement setting for the channel; if that is set to true then your message will be automatically acknowledged on receipt.

Gestión de fallos

If a message produced from a RabbitMQ message is nacked, a failure strategy is applied. The RabbitMQ connector supports three strategies, controlled by the failure-strategy channel setting:

  • fail - fail the application; no more RabbitMQ messages will be processed. The RabbitMQ message is marked as rejected.

  • accept - this strategy marks the RabbitMQ message as accepted. The processing continues ignoring the failure.

  • reject - this strategy marks the RabbitMQ message as rejected (default). The processing continues with the next message.

Sending RabbitMQ messages

Serialización

When sending a Message<T>, the connector converts the message into a RabbitMQ Message. The payload is converted to the RabbitMQ Message body.

T RabbitMQ Message Body

primitive types or UUID/String

String value with content_type set to text/plain

JsonObject o JsonArray

Serialized String payload with content_type set to application/json

io.vertx.mutiny.core.buffer.Buffer

Binary content, with content_type set to application/octet-stream

byte[]

Binary content, with content_type set to application/octet-stream

Cualquier otra clase

The payload is converted to JSON (using a Json Mapper) then serialized with content_type set to application/json

Si la carga útil del mensaje no puede ser serializada a JSON, el mensaje es nacked.

Metadatos de salida

When sending Messages, you can add an instance of OutgoingRabbitMQMetadata to influence how the message is handled by RabbitMQ. For example, you can configure the routing key, timestamp and headers:

final OutgoingRabbitMQMetadata metadata = new OutgoingRabbitMQMetadata.Builder()
        .withHeader("my-header", "xyzzy")
        .withRoutingKey("urgent")
        .withTimestamp(ZonedDateTime.now())
        .build();

// Add `metadata` to the metadata of the outgoing message.
return Message.of("Hello", Metadata.of(metadata));

Agradecimiento

By default, the Reactive Messaging Message is acknowledged when the broker acknowledges the message.

Configuring the RabbitMQ Exchange/Queue

You can configure the RabbitMQ exchange or queue associated with a channel using properties on the channel configuration. incoming channels are mapped to RabbitMQ queues and outgoing channels are mapped to RabbitMQ exchanges. For example:

mp.messaging.incoming.prices.connector=smallrye-rabbitmq
mp.messaging.incoming.prices.queue.name=my-queue

mp.messaging.outgoing.orders.connector=smallrye-rabbitmq
mp.messaging.outgoing.orders.exchange.name=my-order-queue

If the exchange.name or queue.name attribute is not set, the connector uses the channel name.

To use an existing queue, you need to configure the name and set the exchange’s or queue’s declare property to false. For example, if you have a RabbitMQ broker configured with a people exchange and queue, you need the following configuration:

mp.messaging.incoming.people.connector=smallrye-rabbitmq
mp.messaging.incoming.people.queue.name=people
mp.messaging.incoming.people.queue.declare=false

mp.messaging.outgoing.people.connector=smallrye-rabbitmq
mp.messaging.outgoing.people.exchange.name=people
mp.messaging.outgoing.people.exchange.declare=false

Modelo de ejecución y procesamiento por bloqueo

Reactive Messaging invokes your method on an I/O thread. See the Quarkus Reactive Architecture documentation for further details on this topic. But, you often need to combine Reactive Messaging with blocking processing such as database interactions. For this, you need to use the @Blocking annotation indicating that the processing is blocking and should not be run on the caller thread.

Por ejemplo, el siguiente código ilustra cómo puede almacenar las cargas útiles entrantes en una base de datos utilizando Hibernate con Panache:

import io.smallrye.reactive.messaging.annotations.Blocking;
import org.eclipse.microprofile.reactive.messaging.Incoming;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.transaction.Transactional;

@ApplicationScoped
public class PriceStorage {

    @Incoming("prices")
    @Blocking
    @Transactional
    public void store(int priceInUsd) {
        Price price = new Price();
        price.value = priceInUsd;
        price.persist();
    }

}

Hay 2 anotaciones en @Blocking:

  1. io.smallrye.reactive.messaging.annotations.Blocking

  2. io.smallrye.common.annotation.Blocking

They have the same effect. Thus, you can use both. The first one provides more fine-grained tuning such as the worker pool to use and whether it preserves the order. The second one, used also with other reactive features of Quarkus, uses the default worker pool and preserves the order.

@RunOnVirtualThread

For running the blocking processing on Java virtual threads, see the Quarkus Virtual Thread support with Reactive Messaging documentation.

Customizing the underlying RabbitMQ client

The connector uses the Vert.x RabbitMQ client underneath. More details about this client can be found in the Vert.x website.

You can customize the underlying client configuration by producing an instance of RabbitMQOptions as follows:

@Produces
@Identifier("my-named-options")
public RabbitMQOptions getNamedOptions() {
  PemKeyCertOptions keycert = new PemKeyCertOptions()
        .addCertPath("./tls/tls.crt")
        .addKeyPath("./tls/tls.key");
  PemTrustOptions trust = new PemTrustOptions().addCertPath("./tlc/ca.crt");
  // You can use the produced options to configure the TLS connection
  return new RabbitMQOptions()
        .setSsl(true)
        .setPemKeyCertOptions(keycert)
        .setPemTrustOptions(trust)
        .setUser("user1")
        .setPassword("password1")
        .setHost("localhost")
        .setPort(5672)
        .setVirtualHost("vhost1")
        .setConnectionTimeout(6000) // in milliseconds
        .setRequestedHeartbeat(60) // in seconds
        .setHandshakeTimeout(6000) // in milliseconds
        .setRequestedChannelMax(5)
        .setNetworkRecoveryInterval(500) // in milliseconds
        .setAutomaticRecoveryEnabled(true);
}

This instance is retrieved and used to configure the client used by the connector. You need to indicate the name of the client using the client-options-name attribute:

mp.messaging.incoming.prices.client-options-name=my-named-options

Informes de salud

If you use the RabbitMQ connector with the quarkus-smallrye-health extension, it contributes to the readiness and liveness probes. The RabbitMQ connector reports the readiness and liveness of each channel managed by the connector.

To disable health reporting, set the health-enabled attribute for the channel to false.

On the inbound side (receiving messages from RabbitMQ), the check verifies that the receiver is connected to the broker.

On the outbound side (sending records to RabbitMQ), the check verifies that the sender is not disconnected from the broker; the sender may still be in an initialised state (connection not yet attempted), but this is regarded as live/ready.

Note that a message processing failures nacks the message, which is then handled by the failure-strategy. It’s the responsibility of the failure-strategy to report the failure and influence the outcome of the checks. The fail failure strategy reports the failure, and so the check will report the fault.

Dynamic Credentials

Quarkus and the RabbitMQ connector support Vault’s RabbitMQ secrets engine for generating short-lived dynamic credentials. This allows Vault to create and retire RabbitMQ credentials on a regular basis.

First we need to enable Vault’s rabbitmq secret engine, configure it with RabbitMQ’s connection and authentication information, and create a Vault role my-role (replace 10.0.0.3 by the actual host that is running the RabbitMQ container):

vault secrets enable rabbitmq

vault write rabbitmq/config/connection \
    connection_uri=http://10.0.0.3:15672 \
    username=guest \
    password=guest

vault write rabbitmq/roles/my-role \
    vhosts='{"/":{"write": ".*", "read": ".*"}}'

For this use case, user guest configured above needs to be a RabbitMQ admin user with the capability to create credentials.

Then we need to give a read capability to the Quarkus application on path rabbitmq/creds/my-role.

cat <<EOF | vault policy write vault-rabbitmq-policy -
path "secret/data/myapps/vault-rabbitmq-test/*" {
  capabilities = ["read"]
}
path "rabbitmq/creds/my-role" {
  capabilities = [ "read" ]
}
EOF

Now that Vault knows how to create users in RabbitMQ, we need to configure Quarkus to use a credentials-provider for RabbitMQ.

First we tell Quarkus to request dynamic credentials using a credentials-provider named rabbitmq.

quarkus.rabbitmq.credentials-provider = rabbitmq

Next we configure the rabbitmq credentials provider. The credentials-role option must be set to the name of the role we created in Vault, in our case my-role. The credentials-mount option must be set to rabbitmq.

quarkus.vault.credentials-provider.rabbitmq.credentials-role=my-role
quarkus.vault.credentials-provider.rabbitmq.credentials-mount=rabbitmq
The credentials-mount is used directly as the mount of the secret engine in Vault. Here we are using the default mount path of rabbitmq. If the RabbitMQ secret engine was mounted at a custom path, the credentials-mount option must be set to that path instead.

RabbitMQ Connector Configuration Reference

Configuración del canal de entrada

Atributo (alias) Descripción Obligatorio Por defecto

username

(rabbitmq-username)

El nombre de usuario utilizado para autenticarse en el broker

Type: string

falso

password

(rabbitmq-password)

La contraseña utilizada para autenticarse en el broker

Type: string

falso

host

(rabbitmq-host)

El nombre de host del broker

Type: string

falso

localhost

port

(rabbitmq-port)

El puerto del corredor

Type: int

falso

5672

ssl

(rabbitmq-ssl)

Whether the connection should use SSL

Type: boolean

falso

false

trust-all

(rabbitmq-trust-all)

Whether to skip trust certificate verification

Type: boolean

falso

false

trust-store-path

(rabbitmq-trust-store-path)

The path to a JKS trust store

Type: string

falso

trust-store-password

(rabbitmq-trust-store-password)

The password of the JKS trust store

Type: string

falso

credentials-provider-name

(rabbitmq-credentials-provider-name)

The name of the RabbitMQ Credentials Provider bean used to provide dynamic credentials to the RabbitMQ client

Type: string

falso

connection-timeout

The TCP connection timeout (ms); 0 is interpreted as no timeout

Type: int

falso

60000

handshake-timeout

The AMQP 0-9-1 protocol handshake timeout (ms)

Type: int

falso

10000

automatic-recovery-enabled

Whether automatic connection recovery is enabled

Type: boolean

falso

false

automatic-recovery-on-initial-connection

Whether automatic recovery on initial connections is enabled

Type: boolean

falso

true

reconnect-attempts

(rabbitmq-reconnect-attempts)

El número de intentos de reconexión

Type: int

falso

100

reconnect-interval

(rabbitmq-reconnect-interval)

The interval (in seconds) between two reconnection attempts

Type: int

falso

10

network-recovery-interval

How long (ms) will automatic recovery wait before attempting to reconnect

Type: int

falso

5000

user

The AMQP username to use when connecting to the broker

Type: string

falso

guest

include-properties

Whether to include properties when a broker message is passed on the event bus

Type: boolean

falso

false

requested-channel-max

The initially requested maximum channel number

Type: int

falso

2047

requested-heartbeat

The initially requested heartbeat interval (seconds), zero for none

Type: int

falso

60

use-nio

Whether usage of NIO Sockets is enabled

Type: boolean

falso

false

virtual-host

(rabbitmq-virtual-host)

The virtual host to use when connecting to the broker

Type: string

falso

/

exchange.name

The exchange that messages are published to or consumed from. If not set, the channel name is used. If set to "", the default exchange is used

Type: string

falso

exchange.durable

Whether the exchange is durable

Type: boolean

falso

true

exchange.auto-delete

Whether the exchange should be deleted after use

Type: boolean

falso

false

exchange.type

The exchange type: direct, fanout, headers or topic (default)

Type: string

falso

topic

exchange.declare

Whether to declare the exchange; set to false if the exchange is expected to be set up independently

Type: boolean

falso

true

tracing.enabled

Si el rastreo está activado (por defecto) o desactivado

Type: boolean

falso

true

tracing.attribute-headers

A comma-separated list of headers that should be recorded as span attributes. Relevant only if tracing.enabled=true

Type: string

falso

``

queue.name

The queue from which messages are consumed.

Type: string

true

queue.durable

Whether the queue is durable

Type: boolean

falso

true

queue.exclusive

Whether the queue is for exclusive use

Type: boolean

falso

false

queue.auto-delete

Whether the queue should be deleted after use

Type: boolean

falso

false

queue.declare

Whether to declare the queue and binding; set to false if these are expected to be set up independently

Type: boolean

falso

true

queue.ttl

If specified, the time (ms) for which a message can remain in the queue undelivered before it is dead

Type: long

falso

queue.single-active-consumer

If set to true, only one consumer can actively consume messages

Type: boolean

falso

false

queue.x-queue-type

If automatically declare queue, we can choose different types of queue [quorum, classic, stream]

Type: string

falso

classic

queue.x-queue-mode

If automatically declare queue, we can choose different modes of queue [lazy, default]

Type: string

falso

default

max-incoming-internal-queue-size

The maximum size of the incoming internal queue

Type: int

falso

connection-count

The number of RabbitMQ connections to create for consuming from this queue. This might be necessary to consume from a sharded queue with a single client.

Type: int

falso

1

auto-bind-dlq

Whether to automatically declare the DLQ and bind it to the binder DLX

Type: boolean

falso

false

dead-letter-queue-name

The name of the DLQ; if not supplied will default to the queue name with '.dlq' appended

Type: string

falso

dead-letter-exchange

A DLX to assign to the queue. Relevant only if auto-bind-dlq is true

Type: string

falso

DLX

dead-letter-exchange-type

The type of the DLX to assign to the queue. Relevant only if auto-bind-dlq is true

Type: string

falso

direct

dead-letter-routing-key

A dead letter routing key to assign to the queue; if not supplied will default to the queue name

Type: string

falso

dlx.declare

Whether to declare the dead letter exchange binding. Relevant only if auto-bind-dlq is true; set to false if these are expected to be set up independently

Type: boolean

falso

false

dead-letter-queue-type

If automatically declare DLQ, we can choose different types of DLQ [quorum, classic, stream]

Type: string

falso

classic

dead-letter-queue-mode

If automatically declare DLQ, we can choose different modes of DLQ [lazy, default]

Type: string

falso

default

failure-strategy

The failure strategy to apply when a RabbitMQ message is nacked. Accepted values are fail, accept, reject (default)

Type: string

falso

reject

broadcast

Whether the received RabbitMQ messages must be dispatched to multiple subscribers

Type: boolean

falso

false

auto-acknowledgement

Whether the received RabbitMQ messages must be acknowledged when received; if true then delivery constitutes acknowledgement

Type: boolean

falso

false

keep-most-recent

Whether to discard old messages instead of recent ones

Type: boolean

falso

false

routing-keys

A comma-separated list of routing keys to bind the queue to the exchange

Type: string

falso

#

content-type-override

Override the content_type attribute of the incoming message, should be a valid MIME type

Type: string

falso

max-outstanding-messages

The maximum number of outstanding/unacknowledged messages being processed by the connector at a time; must be a positive number

Type: int

falso

Configuración del canal de salida

Atributo (alias) Descripción Obligatorio Por defecto

automatic-recovery-enabled

Whether automatic connection recovery is enabled

Type: boolean

falso

false

automatic-recovery-on-initial-connection

Whether automatic recovery on initial connections is enabled

Type: boolean

falso

true

connection-timeout

The TCP connection timeout (ms); 0 is interpreted as no timeout

Type: int

falso

60000

default-routing-key

The default routing key to use when sending messages to the exchange

Type: string

falso

``

default-ttl

If specified, the time (ms) sent messages can remain in queues undelivered before they are dead

Type: long

falso

exchange.auto-delete

Whether the exchange should be deleted after use

Type: boolean

falso

false

exchange.declare

Whether to declare the exchange; set to false if the exchange is expected to be set up independently

Type: boolean

falso

true

exchange.durable

Whether the exchange is durable

Type: boolean

falso

true

exchange.name

The exchange that messages are published to or consumed from. If not set, the channel name is used. If set to "", the default exchange is used

Type: string

falso

exchange.type

The exchange type: direct, fanout, headers or topic (default)

Type: string

falso

topic

handshake-timeout

The AMQP 0-9-1 protocol handshake timeout (ms)

Type: int

falso

10000

host

(rabbitmq-host)

El nombre de host del broker

Type: string

falso

localhost

include-properties

Whether to include properties when a broker message is passed on the event bus

Type: boolean

falso

false

max-inflight-messages

The maximum number of messages to be written to RabbitMQ concurrently; must be a positive number

Type: long

falso

1024

max-outgoing-internal-queue-size

The maximum size of the outgoing internal queue

Type: int

falso

network-recovery-interval

How long (ms) will automatic recovery wait before attempting to reconnect

Type: int

falso

5000

password

(rabbitmq-password)

La contraseña utilizada para autenticarse en el broker

Type: string

falso

port

(rabbitmq-port)

El puerto del corredor

Type: int

falso

5672

reconnect-attempts

(rabbitmq-reconnect-attempts)

El número de intentos de reconexión

Type: int

falso

100

reconnect-interval

(rabbitmq-reconnect-interval)

The interval (in seconds) between two reconnection attempts

Type: int

falso

10

requested-channel-max

The initially requested maximum channel number

Type: int

falso

2047

requested-heartbeat

The initially requested heartbeat interval (seconds), zero for none

Type: int

falso

60

ssl

(rabbitmq-ssl)

Whether the connection should use SSL

Type: boolean

falso

false

tracing.attribute-headers

A comma-separated list of headers that should be recorded as span attributes. Relevant only if tracing.enabled=true

Type: string

falso

``

tracing.enabled

Si el rastreo está activado (por defecto) o desactivado

Type: boolean

falso

true

trust-all

(rabbitmq-trust-all)

Whether to skip trust certificate verification

Type: boolean

falso

false

trust-store-password

(rabbitmq-trust-store-password)

The password of the JKS trust store

Type: string

falso

trust-store-path

(rabbitmq-trust-store-path)

The path to a JKS trust store

Type: string

falso

credentials-provider-name

(rabbitmq-credentials-provider-name)

The name of the RabbitMQ Credentials Provider bean used to provide dynamic credentials to the RabbitMQ client

Type: string

falso

use-nio

Whether usage of NIO Sockets is enabled

Type: boolean

falso

false

user

The AMQP username to use when connecting to the broker

Type: string

falso

guest

username

(rabbitmq-username)

El nombre de usuario utilizado para autenticarse en el broker

Type: string

falso

virtual-host

(rabbitmq-virtual-host)

The virtual host to use when connecting to the broker

Type: string

falso

/