Publisher confirms report broker acceptance; mandatory returns report unroutable messages, and neither proves the consumer committed its database work.
RabbitTemplate confirms and returns: broker acceptance is not consumer completion
Observe two failure channels
A parcel relay can publish to an exchange that exists but has no matching queue. The broker may confirm accepting that publish while returning the message as unroutable when mandatory returns are enabled. A missing exchange can close the channel instead. Check the correlated confirm and the returned-message result before marking an outbox row delivered. The outbox lease still needs an atomic acknowledgment of the relay's final decision.
Do not infer downstream success
A positive broker confirm says nothing about whether a listener parsed the event or committed a ledger row. Keep distinct states for stored, broker-accepted and business-applied. The consumer's dedup transaction handles retries if the publisher cannot know whether the broker saw an attempt. Use a stable event ID in CorrelationData so callbacks can resolve the right outbox row.
Break routing in a test
Publish one message through a bound routing key and one through an unbound key. Assert the first receives a confirm without return, and the second is observed as returned. Then stop the broker during publish and verify the outbox row remains eligible for retry. These properties enable observation only; callback wiring and persistence still need implementation.
Implementation sketch
spring:
rabbitmq:
publisher-confirm-type: correlated
publisher-returns: true
template:
mandatory: trueCost and verification
Confirms and returns add callback state and broker round trips. Keep a bounded number of outstanding correlations and expire them when the connection fails.
Common Mistakes
- Do not mark an outbox row delivered merely because convertAndSend returned.
- Do not treat a broker confirm as a consumer commit.
- Do not enable returns while leaving mandatory publication disabled for the path that needs routing checks.
Read next
Spring AMQP poison messages: reject, requeue and dead-letter are different decisions, Spring outbox claims: lease expiry and token-fenced acknowledgement, Outbox acknowledgements: require the current lease token, Spring Kafka producer future: observe broker send completion separately from command success.
