Add the rabbitmq module

This commit is contained in:
2026-08-29 09:58:34 +05:30
parent 3a682e496e
commit de9fc5ce4c
27 changed files with 1523 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
[← Exchanges](02-exchanges.md) · [Module README](../README.md) · [Dead-lettering →](04-dead-lettering.md)
# 3. The message that goes nowhere and says nothing
Publish to `orders.direct` with routing key `amend`. No binding matches. The broker discards the
message. `convertAndSend` returns normally. Nothing is logged, by the broker or by Spring, and
the message is gone.
This is correct AMQP behaviour and it is the single most expensive default in RabbitMQ, because
the symptom is "the consumer isn't running" and the cause is three services away.
**Two settings are required, and they live in different places:**
```yaml
spring:
rabbitmq:
publisher-returns: true # on the connection factory
template:
mandatory: true # on the template
```
`publisher-returns` puts the connection into a mode where returns are listened for at all.
`mandatory` asks the broker to return *this* publish if it is unroutable. Setting only
`mandatory` — which is what most examples show — changes nothing, and the test in this module
was written that way first and failed.
Then register a callback:
```java
template.setReturnsCallback((returned) -> log.error("unroutable: exchange={} key={} {} {}",
returned.getExchange(), returned.getRoutingKey(),
returned.getReplyCode(), returned.getReplyText()));
```
From [`docs/output/unroutable.txt`](output/unroutable.txt):
```
replyCode 312
replyText NO_ROUTE
exchange orders.direct
routingKey amend
```
`312 NO_ROUTE` is the code worth putting in an alert.
## What returns still do not give you
The callback fires **asynchronously, on the connection's thread**. `convertAndSend` had already
returned successfully by then. So a return tells you a message was lost; it does not let you
stop the caller from believing it succeeded.
If the caller must know, you need **publisher confirms** as well:
```yaml
spring:
rabbitmq:
publisher-confirm-type: correlated
```
Confirms and returns answer different questions, and you usually want both:
| | answers |
|---|---|
| **return** | the broker had nowhere to route this |
| **confirm** | the broker took responsibility for this (`ack`), or refused it (`nack`) |
A message that is unroutable gets a **return followed by an `ack`** — the broker successfully did
nothing with it. So a confirm alone will not tell you the message vanished, which is the trap
inside the trap.
## The alternate exchange
The topology-level version of the same fix: give an exchange an `alternate-exchange` argument and
unroutable messages go there instead of being dropped, with no publisher-side configuration at
all. It costs one exchange and one queue, and it catches the publishes made by services that
forgot to set `mandatory`.
[Dead-lettering →](04-dead-lettering.md)