AMQP: Support CorrelationData Message Headers

In preparation for https://github.com/spring-cloud/spring-cloud-stream-binder-rabbit/issues/303

Now that `CorrelationData` has a `Future<?>`, users might simply add
correlation data in a header and not receive confirm/return messages.

- No longer require channels for returns and confirms
- don't build the confirm message if there are no channels
- reduce the log level for no channels to DEBUG
- complete the user's future when a message is returned (async GW)

* Fix typo.
This commit is contained in:
Gary Russell
2020-07-31 10:00:18 -04:00
committed by GitHub
parent f5522949f3
commit 8cf6ff0462
6 changed files with 161 additions and 28 deletions

View File

@@ -601,18 +601,22 @@ Version 4.1 introduced the `amqp_publishConfirmNackCause` message header.
It contains the `cause` of a 'nack' for a publisher confirmation.
Starting with version 4.2, if the expression resolves to a `Message<?>` instance (such as `#this`), the message emitted on the `ack`/`nack` channel is based on that message, with the additional header(s) added.
Previously, a new message was created with the correlation data as its payload, regardless of type.
Also see <<alternative-confirms-returns>>.
Optional.
<11> The channel to which positive (`ack`) publisher confirms are sent.
The payload is the correlation data defined by the `confirm-correlation-expression`.
If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `true`.
Also see <<alternative-confirms-returns>>.
Optional (the default is `nullChannel`).
<12> The channel to which negative (`nack`) publisher confirmations are sent.
The payload is the correlation data defined by the `confirm-correlation-expression` (if there is no `ErrorMessageStrategy` configured).
If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `false`.
When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `NackedAmqpMessageException` payload.
Also see <<alternative-confirms-returns>>.
Optional (the default is `nullChannel`).
<13> When set, the adapter will synthesize a negative acknowledgment (nack) if a publisher confirm is not received within this time in milliseconds.
Pending confirms are checked every 50% of this value, so the actual time a nack is sent will be between 1x and 1.5x this value.
Also see <<alternative-confirms-returns>>.
Default none (nacks will not be generated).
<14> When set to true, the calling thread will block, waiting for a publisher confirmation.
This requires a `RabbitTemplate` configured for confirms as well as a `confirm-correlation-expression`.
@@ -623,6 +627,7 @@ If returns are enabled and a message is returned, or any other exception occurs
When provided, the underlying AMQP template is configured to return undeliverable messages to the adapter.
When there is no `ErrorMessageStrategy` configured, the message is constructed from the data received from AMQP, with the following additional headers: `amqp_returnReplyCode`, `amqp_returnReplyText`, `amqp_returnExchange`, `amqp_returnRoutingKey`.
When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `ReturnedAmqpMessageException` payload.
Also see <<alternative-confirms-returns>>.
Optional.
<16> A reference to an `ErrorMessageStrategy` implementation used to build `ErrorMessage` instances when sending returned or negatively acknowledged messages.
<17> A reference to an `AmqpHeaderMapper` to use when sending AMQP Messages.
@@ -815,15 +820,18 @@ Examples: `headers['myCorrelationData']` and `payload`.
If the expression resolves to a `Message<?>` instance (such as `#this`), the message
emitted on the `ack`/`nack` channel is based on that message, with the additional headers added.
Previously, a new message was created with the correlation data as its payload, regardless of type.
Also see <<alternative-confirms-returns>>.
Optional.
<14> The channel to which positive (`ack`) publisher confirmations are sent.
The payload is the correlation data defined by `confirm-correlation-expression`.
If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `true`.
Also see <<alternative-confirms-returns>>.
Optional (the default is `nullChannel`).
<15> The channel to which negative (`nack`) publisher confirmations are sent.
The payload is the correlation data defined by `confirm-correlation-expression` (if there is no `ErrorMessageStrategy` configured).
If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `false`.
When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `NackedAmqpMessageException` payload.
Also see <<alternative-confirms-returns>>.
Optional (the default is `nullChannel`).
<16> When set, the gateway will synthesize a negative acknowledgment (nack) if a publisher confirm is not received within this time in milliseconds.
Pending confirms are checked every 50% of this value, so the actual time a nack is sent will be between 1x and 1.5x this value.
@@ -832,6 +840,7 @@ Default none (nacks will not be generated).
When provided, the underlying AMQP template is configured to return undeliverable messages to the adapter.
When there is no `ErrorMessageStrategy` configured, the message is constructed from the data received from AMQP, with the following additional headers: `amqp_returnReplyCode`, `amqp_returnReplyText`, `amqp_returnExchange`, and `amqp_returnRoutingKey`.
When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `ReturnedAmqpMessageException` payload.
Also see <<alternative-confirms-returns>>.
Optional.
<18> A reference to an `ErrorMessageStrategy` implementation used to build `ErrorMessage` instances when sending returned or negatively acknowledged messages.
<19> When set to `false`, the endpoint attempts to connect to the broker during application context initialization.
@@ -1026,23 +1035,28 @@ The payload of the confirmation is the correlation data as defined by this expre
For `nack` instances, an additional header (`amqp_publishConfirmNackCause`) is provided.
Examples: `headers['myCorrelationData']`, `payload`.
If the expression resolves to a `Message<?>` instance (such as "`#this`"), the message emitted on the `ack`/`nack` channel is based on that message, with the additional headers added.
Also see <<alternative-confirms-returns>>.
Optional.
<14> The channel to which positive (`ack`) publisher confirmations are sent.
The payload is the correlation data defined by the `confirm-correlation-expression`.
Requires the underlying `AsyncRabbitTemplate` to have its `enableConfirms` property set to `true`.
Also see <<alternative-confirms-returns>>.
Optional (the default is `nullChannel`).
<15> Since version 4.2.
The channel to which negative (`nack`) publisher confirmations are sent.
The payload is the correlation data defined by the `confirm-correlation-expression`.
Requires the underlying `AsyncRabbitTemplate` to have its `enableConfirms` property set to `true`.
Also see <<alternative-confirms-returns>>.
Optional (the default is `nullChannel`).
<16> When set, the gateway will synthesize a negative acknowledgment (nack) if a publisher confirm is not received within this time in milliseconds.
Pending confirms are checked every 50% of this value, so the actual time a nack is sent will be between 1x and 1.5x this value.
Also see <<alternative-confirms-returns>>.
Default none (nacks will not be generated).
<17> The channel to which returned messages are sent.
When provided, the underlying AMQP template is configured to return undeliverable messages to the gateway.
The message is constructed from the data received from AMQP, with the following additional headers: `amqp_returnReplyCode`, `amqp_returnReplyText`, `amqp_returnExchange`, and `amqp_returnRoutingKey`.
Requires the underlying `AsyncRabbitTemplate` to have its `mandatory` property set to `true`.
Also see <<alternative-confirms-returns>>.
Optional.
<18> When set to `false`, the endpoint tries to connect to the broker during application context initialization.
Doing so allows "`fail fast`" detection of bad configuration, by logging an error message if the broker is down.
@@ -1137,6 +1151,39 @@ public class AmqpAsyncApplication {
----
====
[[alternative-confirms-returns]]
=== Alternative Mechanism for Publisher Confirms and Returns
When the connection factory is configured for publisher confirms and returns, the sections above discuss the configuration of message channels to receive the confirms and returns asynchronously.
Starting with version 5.4, there is an additional mechanism which is generally easier to use.
In this case, do not configure a `confirm-correlation-expression` or the confirm and return channels.
Instead, add a `CorrelationData` instance in the `AmqpHeaders.PUBLISH_CONFIRM_CORRELATION` header; you can then wait for the result(s) later, by checking the state of the future in the `CorrelationData` instances for which you have sent messages.
The `returnedMessage` field will always be populated (if a message is returned) before the future is completed.
====
[source, java]
----
CorrelationData corr = new CorrelationData("someId"); // <--- Unique "id" is required for returns
someFlow.getInputChannel().send(MessageBuilder.withPayload("test")
.setHeader("rk", "someKeyThatWontRoute")
.setHeader(AmqpHeaders.PUBLISH_CONFIRM_CORRELATION, corr)
.build());
...
try {
Confirm Confirm = corr.getFuture().get(10, TimeUnit.SECONDS);
Message returned = corr.getReturnedMessage();
if (returned !- null) {
// meessage could not be routed
}
}
catch { ... }
----
====
To improve performance, you may wish to send multiple messages and wait for the confirmations later, rather than one-at-a-time.
The returned message is the raw message after conversion; you can subclass `CorrelationData` with whatever additional data you need.
[[amqp-conversion-inbound]]
=== Inbound Message Conversion

View File

@@ -60,3 +60,8 @@ See <<./ip.adoc#ip-collaborating-adapters,Collaborating Channel Adapters>> and <
The `spring-integration-rmi` module is deprecated with no replacement and is going to be removed in the next major version.
See <<./rmi.adoc#rmi, RMI Support>> for more information.
=== AMQP Changes
The outbound endpoints now have a new mechanism for handling publisher confirms and returns.
See <<./amqp.adoc#alternative-confirms-returns,Alternative Mechanism for Publisher Confirms and Returns>> for more information.