KItis
KItis

Reputation: 5646

Spring boot JMS : How not to lose jms message when internal application error happens at the JMS receiver

If JMS receiver fails due to some reason like database connection failure, then JMS message will be lost. could anybody suggest me what is the common solution avoid losing JMS messages with spring boot application

Should I resend the message back to the queue where it originated in case of error while processing the message at the receiver end?

Here is my source code for the scenario.

@SpringBootApplication
public class MainApp {

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

    @Bean
    public JmsListenerContainerFactory<?> sdbFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        // This provides all boot's default to this factory, including the message converter
        configurer.configure(factory, connectionFactory);
        // You could still override some of Boot's default if necessary.
        return factory;
    }

    @Bean
    public Queue queue() {
        return new ActiveMQQueue("sdb.orderQueue");
    }



    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

    @Bean
    public ModelMapper mapper() {
        ModelMapper mapper = new ModelMapper();
        mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        return mapper;
    }

}

producer

@RestController
@RequestMapping("/transaction")
public class OrderTransactionController {

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    private static final Logger LOGGER =
            LoggerFactory.getLogger(OrderTransactionController.class);

    @PostMapping("/send")
    public void send(@RequestBody OrderDTO order)  {
        LOGGER.info("Sending a transaction."+ order);
        jmsMessagingTemplate.convertAndSend("sdb.orderQueue", order);
    }
}

consumer

@Component
public class OrderMessageReceiver {

    @Autowired
    OrderService service;

    @Autowired
    ModelMapper modelMapper;

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    private static final Logger LOGGER =
            LoggerFactory.getLogger(OrderMessageReceiver.class);

    @JmsListener(destination = "sdb.orderQueue", containerFactory = "sdbFactory")
    public void receiveQueue(OrderDTO order) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ModelMapper modelMapper = new ModelMapper();

        OrderEntity orderEntity = modelMapper.map(order, OrderEntity.class);
        try {
            service.createOrder(orderEntity);
        } catch (Exception e) {
            LOGGER.error("Error happend while trying to persist order : {} error is : {}",order, e);


        }
    }


}

Upvotes: 0

Views: 2152

Answers (1)

Gary Russell
Gary Russell

Reputation: 174759

You need to show how you are using it, together with configuration but, by default, with the DefaultMessageListenerContainer the session will be transacted so if the listener throws an exception to the container the transaction will roll back and the message added back to the queue.

If the listener exits normally, the transaction will commit and the message removed.

Upvotes: 1

Related Questions