Skip to content
Advertisement

Stop receiving again and again messages in consumer of the queue when an exception occurs in Spring JMS

I send a message from the sender application as below.

    @GetMapping("send/event")
    public void sendEvent() {
        try {
            String stringEvent = objectMapper.writeValueAsString(getEvent());
            jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
            jmsTemplate.setSessionTransacted(false);
            jmsTemplate.convertAndSend(SEND_QUEUE_NAME, stringEvent);
        } catch (JmsException | JsonProcessingException e) {
            e.printStackTrace();
        }
    }

And in the receiver application, I receive the message as below.

    @Override
    @JmsListener(destination = "${mq.receive_queue}")
    public void receive(Message message) {
        try {
            String jsonEvent = ((TextMessage) message).getText();
            Event event = objectMapper.readValue(jsonEvent, Event.class);
            System.out.println(event.toString());
            message.acknowledge();
            validateEventRequest(event);
        } catch (JMSException | IOException e) {
            e.printStackTrace();
        }
    }

The main problem is when the validateEventRequest(event); has called. Because in this method, I have several services and scenarios that might raise an exception. I don’t want if an exception threw, the message rollback to the queue and receive again. I just want to consume the message completely when an exception occurs. Because of that, I added these lines to the sender application.

  jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
  jmsTemplate.setSessionTransacted(false);

But nothing changes. I appreciate if anyone has idea about this.

Additional information
I called these in receive method of the receiver application

int deliveryMode = jmsTemplate.getDeliveryMode(); -->2
int sessionAcknowledgeMode = jmsTemplate.getSessionAcknowledgeMode(); -->1
int jmsDeliveryMode = message.getJMSDeliveryMode(); -->2
boolean jmsRedelivered = message.getJMSRedelivered(); -->true

Advertisement

Answer

It’s likely that your validateEventRequest(event) is throwing something other than JMSException or IOException (or one of their subclasses) which means the catch in your receive will not actually catch it. I believe that when this exception is thrown out of your receive method that will trigger redelivery on the message. I recommend you catch the more generic Exception instead, e.g.:

@Override
@JmsListener(destination = "${mq.receive_queue}")
public void receive(Message message) {
    try {
        String jsonEvent = ((TextMessage) message).getText();
        Event event = objectMapper.readValue(jsonEvent, Event.class);
        System.out.println(event.toString());
        message.acknowledge();
        validateEventRequest(event);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Also, it’s worth noting that changing how the message is sent has no impact on how the message is received. If you want to change how the message is received then you need to change the receiver application.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement