spring-projects / spring-amqp

Spring AMQP - support for Spring programming model with AMQP, especially but not limited to RabbitMQ
https://spring.io/projects/spring-amqp
Apache License 2.0
809 stars 624 forks source link

RabbitTemplate is not fully data safe #1543

Closed lowcasz closed 1 year ago

lowcasz commented 1 year ago

Version: 3.0.0 and earlier

Description: Using RabbitTemplate send() or convertAndSend() I expect message is succesfully sent to server and wait there for consumers, but there are cases when publish request is rejected by server, but send method was succesfully finished without any exception. It is very important when this mechanism is used to propagate object changes.

In very popular event chain: REST endpoint handling user changes >> app save changed object in DB >> app propagate changes to other microservices >> generate response with HTTP status of this operation In this situation I can't rollback changes in DB and handle error to return appropriate operation HTTP status. Everything looks potentially ok, then I read about logged error by ChannelListener only.

Reproduce: Send message into exchange which is not defined on server.

Expected: RabbitTemplate::send method should wait by default for broker server response until publisher request was accepted.

Sample: Start default docker RabbitMQ instance without any additional configuration

docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.11-management

And use sample project with not default exchange: https://github.com/spring-projects/spring-amqp-samples

garyrussell commented 1 year ago

Use publisher confirms and returns to verify delivery.

https://docs.spring.io/spring-amqp/docs/current/reference/html/#cf-pub-conf-ret

Example here: https://github.com/spring-projects/spring-amqp-samples/tree/main/spring-rabbit-confirms-returns

garyrussell commented 1 year ago

Note that for the missing exchange condition, you won't get a returned message, but the confirm.isAck() will be false.

garyrussell commented 1 year ago

More docs: https://docs.spring.io/spring-amqp/docs/current/reference/html/#template-confirms

lowcasz commented 1 year ago

If I understand it right it waits for all consumer confirm responses, but only broker server confirmation is required. I don't want stop user request endpoint until all other microservices will get changes. Any service can be shut down and I don't wait for them as publisher. It is job of the message broker. Successful sending the message to broker server is totally enough.

lowcasz commented 1 year ago

In my opinion it should be default setting if AMQP protocol was invented for data safe communication. In performance broker as Kafka I understand this behavior, but not here.

garyrussell commented 1 year ago

No; it has nothing to do with consumers; producers and consumers are completely independent (loose coupling). There is no mechanism to tell a producer whether or not a consumer is actually consuming.

The confirm is sent to the producer after the message has been secured in at least one queue. If the message is unroutable (exchange exists but no queue), you get a positive confirm (and a returned message). If you send to a non-existent exchange, you get a negative confirm.

Spring provides convenient mechanisms to correlate confirms with sends.

lowcasz commented 1 year ago

Thank you! :)

lowcasz commented 1 year ago

In my opinion it should be default setting if AMQP protocol was invented for data safe communication. In performance broker as Kafka I understand this behavior, but not here.

But I still think It should be default behavior. And corelated data should be created in send method if is null. And wait for it according parameter setting, but wait by default.

garyrussell commented 1 year ago

That may be your opinion, but it will significantly decrease performance, requiring a round trip to the broker for each send - most applications that require confirmation will accumulate the correlations and wait for them to complete later. RabbitMQ is designed to be much more performant than, say, JMS, which requires a round trip for each send.

lowcasz commented 1 year ago

Ok. It's fully closed now. Thank you again! :)