nikkidtosh
nikkidtosh

Reputation: 83

How to read x-death header of a RabbitMQ dead-lettered message using Spring Boot?

I am trying to implement re-routing of dead-lettered messages as described in this answer. I am using Spring config. I have no idea on how to read the headers to get the original routing key and original queue. The following is my config:

@Configuration
public class NotifEngineRabbitMQConfig {
    @Bean
    public MessageHandler handler(){
        return new MessageHandler();
    }
    @Bean
    public Jackson2JsonMessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
    @Bean
    public MessageListenerAdapter messageListenerAdapter(){
        return new MessageListenerAdapter(handler(), messageConverter());
    }

    /**
     * Listens for incoming messages
     * Allows multiple queue to listen to
     * */
    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.addQueueNames(QUEUE_TO_LISTEN_TO.split(","));
        container.setMessageListener(messageListenerAdapter());
        container.setConnectionFactory(rabbitConnectionFactory());
        container.setDefaultRequeueRejected(false);
        return container;
    }

    @Bean
    public ConnectionFactory rabbitConnectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory(HOST);
        factory.setUsername(USERNAME);
        factory.setPassword(PASSWORD);
        return factory;
    }

}

Upvotes: 4

Views: 8097

Answers (2)

josemmg
josemmg

Reputation: 1

Gary's answer is the right one. Just a little detail, the type of xDeath is better to be ArrayList<HashMap<String,*>> instead List<String> xDeath. Then you can access any field by doing something like: xDeath.first().get("count")

Upvotes: 0

Gary Russell
Gary Russell

Reputation: 174554

The headers are not available using "old" style Pojo messaging (with a MessageListenerAdapter). You need to implement MessageListener which gives you access to the headers.

However, you will need to invoke the converter yourself in that case and, if you are using request/reply messaging, you lose the reply mechanism within the adapter and you have to send the reply yourself.

Alternatively, you can use a custom message converter and "enhance" the converted object with the header after invoking the standard converter.

Consider instead using the newer style POJO messaging with @RabbitListener - it gives you access to the headers and has request/reply capability.

Here's an example:

@SpringBootApplication
public class So37581560Application {

    public static void main(String[] args) {
        SpringApplication.run(So37581560Application.class, args);
    }

    @Bean
    public FooListener fooListener() {
        return new FooListener();
    }

    public static class FooListener {

        @RabbitListener(queues="foo")
        public void pojoListener(String body, 
                   @Header(required = false, name = "x-death") List<String> xDeath) {
            System.out.println(body + ":" + (xDeath == null ? "" : xDeath));
        }

    }

}

Result:

Foo:[{reason=expired, count=1, exchange=, time=Thu Jun 02 08:44:19 EDT 2016, routing-keys=[bar], queue=bar}]

Upvotes: 3

Related Questions