skip to content

Show how to configure a RabbitTemplate for correlated publisher confirms and returns, and explain what each piece does.

level: middleimportance: should knowfreq 38%

answer

  1. two places: factory + template
  2. factory: ConfirmType.CORRELATED + publisherReturns(true)
  3. template: setMandatory + setConfirmCallback + setReturnsCallback
  4. confirm cb: (cd, ack, cause); returns cb: ReturnedMessage
  5. Boot props: publisher-confirm-type=correlated, publisher-returns=true

basics

~10 s

Set ConfirmType.CORRELATED and publisherReturns(true) on the CachingConnectionFactory, then on the RabbitTemplate call setMandatory(true), setConfirmCallback(...) for acks/nacks, and setReturnsCallback(...) for unroutable messages.

solid answer

~40 s

Confirms and returns are enabled in two places. On the CachingConnectionFactory you call setPublisherConfirmType(ConfirmType.CORRELATED) (so confirms carry the CorrelationData) and setPublisherReturns(true) (so unroutable messages come back). On the RabbitTemplate that uses that factory you call setMandatory(true) so the broker returns unroutable messages, setConfirmCallback((cd, ack, cause) -> ...) to handle acks/nacks per message, and setReturnsCallback(returned -> ...) to handle ReturnedMessage for unroutable sends. At send time you pass a CorrelationData so the confirm callback can identify the message. The confirm callback distinguishes ack from nack; the returns callback fires only for unroutable mandatory messages. Keep both callbacks fast and thread-safe since they run on amqp threads.

go deeper

for a junior

Know the two callbacks exist and roughly what each handles.

for a middle

Wire both factory switches and all three template settings correctly and send with CorrelationData.

for a senior

Explain the single-callback constraint, thread model, and the Boot property equivalents.

for a principal

Standardize this config across services and integrate the callbacks with an outbox/observability layer.

## Two-place configuration Reliable publishing needs settings on **both** the connection factory and the template — a common source of 'my callback never fires' bugs. ### On the CachingConnectionFactory - `setPublisherConfirmType(ConfirmType.CORRELATED)` — turns on confirms and makes them carry the `CorrelationData` you attach at send time. `SIMPLE` would enable only blocking `waitForConfirms`; `NONE` disables confirms. - `setPublisherReturns(true)` — enables delivery of returned (unroutable) messages to the template's returns callback. ### On the RabbitTemplate - `setMandatory(true)` — sets the AMQP mandatory flag so the broker returns unroutable messages instead of dropping them. - `setConfirmCallback(ConfirmCallback)` — invoked with `(CorrelationData correlationData, boolean ack, String cause)` for every confirm; `ack=false` is a nack and `cause` explains it. - `setReturnsCallback(ReturnsCallback)` — invoked with a `ReturnedMessage` for each unroutable mandatory message. ## Full example ```java @Configuration public class RabbitConfig { @Bean CachingConnectionFactory connectionFactory() { CachingConnectionFactory cf = new CachingConnectionFactory("localhost"); cf.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED); cf.setPublisherReturns(true); return cf; } @Bean RabbitTemplate rabbitTemplate(CachingConnectionFactory cf) { RabbitTemplate template = new RabbitTemplate(cf); template.setMandatory(true); template.setConfirmCallback((correlationData, ack, cause) -> { if (ack) { log.info("Confirmed: {}", correlationData != null ? correlationData.getId() : "n/a"); } else { log.error("Nacked: {} cause={}", correlationData != null ? correlationData.getId() : "n/a", cause); } }); template.setReturnsCallback(returned -> log.warn("Returned (unroutable): rk={} code={} text={}", returned.getRoutingKey(), returned.getReplyCode(), returned.getReplyText())); return template; } } // sending with correlation CorrelationData cd = new CorrelationData("evt-" + id); rabbitTemplate.convertAndSend("app.ex", "app.rk", payload, cd); ``` ## Spring Boot shortcut With Spring Boot you can set `spring.rabbitmq.publisher-confirm-type=correlated` and `spring.rabbitmq.publisher-returns=true` in properties, and the auto-configured `CachingConnectionFactory` picks them up; you still register the callbacks on the template (or `spring.rabbitmq.template.mandatory=true`). ## Gotchas - Only **one** `ConfirmCallback` and **one** `ReturnsCallback` per template — for per-message logic prefer the `CorrelationData` future or dispatch inside the single callback by id. - Callbacks run on **amqp/listener threads** — don't block them; hand heavy work to an executor. - Setting `setMandatory(true)` without `setPublisherReturns(true)` means returns never arrive. - `correlationData` can be `null` in the confirm callback if you didn't attach one — guard for it. ## When to use This wiring is the baseline for any producer that must know its sends succeeded — enable it once in config and always send with a CorrelationData for critical messages.

  • How many ConfirmCallbacks can a single RabbitTemplate have?
    One. For per-message handling, dispatch by CorrelationData id inside that single callback or use each CorrelationData's own CompletableFuture.
  • What are the equivalent Spring Boot properties?
    spring.rabbitmq.publisher-confirm-type=correlated, spring.rabbitmq.publisher-returns=true, and spring.rabbitmq.template.mandatory=true; you still register the callbacks in code.

saying these in an interview costs you the question

  • Setting callbacks but forgetting the connection-factory switches
  • Registering multiple ConfirmCallbacks expecting all to fire
  • Blocking inside the callback (runs on an amqp thread)
  • Not null-checking correlationData in the confirm callback

context