spring-projects / spring-amqp

Spring AMQP - support for Spring programming model with AMQP, especially but not limited to RabbitMQ

Home Page:https://spring.io/projects/spring-amqp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Fix RabbitMQ x-death header documentation

ansd opened this issue · comments

The Spring Cloud Stream RabbitMQ Binder Reference Guide recommends that the AMQP 0.9.1 client re-publishes a message with the x-death header it received from RabbitMQ in order to determine the number of times (count) the message was received and re-published to RabbitMQ, see rabbitmq/rabbitmq-server#10709 (comment)

We consider this an anti-pattern or even bug because AMQP 0.9.1 headers prefixed with x- including x-death "belong" to the broker and are not meant to be specially parsed and interpreted by the broker when received from an AMQP 0.9.1 client.

Hence, as explained here, we recommend changing the documentation to instead use some custom non x-header to determine how often a message was re-published from the client to the broker.

Starting with RabbitMQ 4.0, the current documented pattern by Spring Cloud Stream RabbitMQ Binder Reference Guide will break.

I'm not fully sure what you find as a wrong recommendation. I don't see any sentence in that doc which says something like re-publishes a message with the x-death header it received from RabbitMQ.
It indeed looks like we rely on the x-death to determine the count and sometimes an original exchange/routing-key, but no where we say explicitly that this header has to be set by the client code.

I think we just followed Dead Letter Exchanges docs to deal with expectations after DLX.

Thanks

Thanks @artembilan for the clarification.
I got misled by the comment from @dvovney in rabbitmq/rabbitmq-server#10709 (comment)
I close this issue for now.

Apparently x-death.count is not going to be incremented from now on. Therefore we indeed have to come up with other strategy in the ConditionalRejectingErrorHandler.
Plus fix docs respectively here and there in Spring Cloud Stream.
See more info in the: spring-cloud/spring-cloud-stream#2939

@ansd ,

Would you mind, please, confirm that x-death header is still going to be present in the consumed message?
Apparently we have a logic like this:

	/**
	 * Set to false to disable the (now) default behavior of logging and discarding
	 * messages that cause fatal exceptions and have an `x-death` header; which
	 * usually means that the message has been republished after previously being
	 * sent to a DLQ.
	 * @param discardFatalsWithXDeath false to disable.
	 * @since 2.1
	 */
	public void setDiscardFatalsWithXDeath(boolean discardFatalsWithXDeath) {

Apparently we don't deal (and don't talk) about its count property anywhere in Spring AMQP.

Thanks

I probably won't mind to implement some new strategy for header different from x-death, but it looks like for now we have to just fix docs in Spring Cloud Stream as you have talked originally.

Starting with RabbitMQ 3.13, the count parameter in x-death header is no longer incremented. This breaks SCSt applications that relied on this header and parameter to keep track of retry attempts. Note that spring-amqp/SCSt already sets another header x-exception-stacktrace with Java exception stacktrace that resulted in the message being dead lettered. We will need another similar header, for example, x-retry-attempt to carry the retry attempt (i.e., number of times the message is published to DLQ). Note that RabbitMQ is discouraging usage of x- prefixed headers, so both x-exception-stacktrace and x-retry-attempt should be renamed to something else

I see. Would it be OK to have them as something like spring-exception-stacktrace and spring-retry-attempt respectively?
We have a number of others in the RepublishMessageRecoverer:

	public static final String X_EXCEPTION_STACKTRACE = "x-exception-stacktrace";

	public static final String X_EXCEPTION_MESSAGE = "x-exception-message";

	public static final String X_ORIGINAL_EXCHANGE = "x-original-exchange";

	public static final String X_ORIGINAL_ROUTING_KEY = "x-original-routingKey";

@artembilan

Would you mind, please, confirm that x-death header is still going to be present in the consumed message?

Yes, the x-death header including its count field will be present in a consumed message (if this message got previously dead lettered).

The only thing that changes in RabbitMQ 3.13 is that RabbitMQ (upon receiving) won't interpret anymore the x-death header when a client (re)publishes a message.

So, if there is any code or documentation within Spring that causes messages being published to RabbitMQ to have the x-death header set, this will need to change.
If there is no such code or documentation, nothing within Spring needs to change.

Yeah... Nothing to fix here.