What are RabbitMQ publisher confirms in Spring AMQP, and what problem do they solve?
answer
- fire-and-forget -> async ack
- setPublisherConfirmType(CORRELATED)
- ack = broker accepted, nack = rare failure
- confirm != consumer processed
- unroutable is still acked
basics
~20 sBy default, sending a message via RabbitTemplate doesn't tell you if the broker actually received it. Publisher confirms make the broker send back an async ack (or nack) per message, so the producer knows the send succeeded.
solid answer
~40 sPlain AMQP publishing is fire-and-forget: RabbitTemplate.convertAndSend() returns as soon as the message leaves the client, giving no proof the broker stored it. Publisher confirms are a RabbitMQ extension where the broker asynchronously returns an ack once it has accepted the message (persisted it for durable messages, or routed it to queues). In Spring AMQP you enable it on the CachingConnectionFactory with setPublisherConfirmType(ConfirmType.CORRELATED), then register a RabbitTemplate.ConfirmCallback (or use the CorrelationData future). You get a callback with (correlationData, ack, cause): ack=true means the broker accepted it, ack=false (a nack) means it couldn't. This closes the reliability gap between 'my send call returned' and 'the broker has the message', which matters for anything that must not silently lose data.
go deeper
Know that plain sends are fire-and-forget and confirms give an async ack/nack from the broker.
Enable via setPublisherConfirmType(CORRELATED) and register a ConfirmCallback; understand ack vs nack.
Distinguish confirm (broker accepted) from routing (mandatory/returns) and from consumer ack; know callbacks run on amqp threads.
Reason about end-to-end guarantees, timeout handling, and combining confirms with persistence and returns for at-least-once producing.
## The problem With raw AMQP, `basic.publish` has no response. When you call `rabbitTemplate.convertAndSend(exchange, routingKey, payload)`, the method returns as soon as the bytes are handed to the client library's channel. If the broker crashes, is out of disk, or the connection drops mid-flight, the producer never finds out — the message is silently lost. This is 'fire and forget'. ## Publisher confirms **Publisher confirms** (a.k.a. 'confirms' or 'publisher acknowledgements') are a RabbitMQ protocol extension. When enabled on a channel, the broker sends back an **asynchronous acknowledgement** for each published message: - **ack** — the broker has taken responsibility for the message. For a persistent message routed to a durable queue, this means it was written to disk; for a transient message it means it was routed to (accepted by) all the matching queues. - **nack** — the broker could NOT take responsibility (e.g. an internal error, out of resources). Nacks are rare. Confirms are **asynchronous and out-of-band**: publishing stays fast; the acks stream back separately, possibly batched, and not necessarily in send order. ## Enabling it in Spring AMQP Confirms are configured on the `CachingConnectionFactory`: ```java CachingConnectionFactory cf = new CachingConnectionFactory("localhost"); cf.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED); ``` Three modes: - `ConfirmType.NONE` (default) — confirms off. - `ConfirmType.SIMPLE` — enables confirms and lets you call `channel.waitForConfirms()` via `rabbitTemplate.invoke(...)` for a synchronous, blocking wait. - `ConfirmType.CORRELATED` — enables confirms and delivers the result to a callback, carrying a `CorrelationData` you attached at send time so you can match the ack to the specific message. Then on the `RabbitTemplate` you register a `RabbitTemplate.ConfirmCallback`: ```java template.setConfirmCallback((correlationData, ack, cause) -> { if (ack) { /* broker accepted */ } else { /* nack: cause has the reason */ } }); ``` ## What a confirm does and does NOT mean - It **does** mean the broker received/stored/routed the message. - It does **not** mean any consumer processed it — that's consumer acknowledgements, a separate concept. - An ack does **not** mean the message reached a queue if there was no matching queue: an unroutable message is still **acked** (the broker accepted it, then dropped it). Detecting 'accepted but not routed to any queue' needs the **mandatory flag + returns**, which is a separate mechanism. ## Gotchas - Requires the `CachingConnectionFactory` (channels must be cached/tracked). - Callbacks run on a **listener/amqp thread**, not your publishing thread — keep them fast and thread-safe. - There is no automatic timeout: if a confirm never arrives (connection lost), your callback simply never fires unless you add your own timeout handling. ## When to use Use confirms whenever losing a produced message is unacceptable (payments, orders, event sourcing). Combine with **persistent messages + durable queues + mandatory returns** for end-to-end producer reliability.
- Does an ack guarantee a consumer processed the message?No. A confirm only means the broker accepted/stored/routed the message. Whether a consumer received and processed it is a separate concern handled by consumer acknowledgements.
- What's the difference between ConfirmType.SIMPLE and ConfirmType.CORRELATED?SIMPLE enables a synchronous blocking wait via channel.waitForConfirms() (through template.invoke). CORRELATED enables async callbacks that carry the CorrelationData you attached, so you can match each ack to its message.
saying these in an interview costs you the question
- Thinking a publisher confirm means a consumer received the message
- Believing convertAndSend already blocks until the broker confirms
- Assuming an unroutable message produces a nack (it's actually acked)
- Not knowing confirms require the CachingConnectionFactory to be configured