2.8 KiB
← Exchanges · Module README · Dead-lettering →
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:
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:
template.setReturnsCallback((returned) -> log.error("unroutable: exchange={} key={} {} {}",
returned.getExchange(), returned.getRoutingKey(),
returned.getReplyCode(), returned.getReplyText()));
From docs/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:
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.