Search code examples
javaspring-bootspring-jmssolace

Redeliver message in JMS


I am trying to read a message from Solace. I am able to read message successfully, but suppose while reading/processing the message the app crashes. How can I read that message again? With my below code I am not able to read that message again. Below is my configuration:

@JmsListener(destination = "myqueue", containerFactory = "jmsContainer", concurrency = "5-10")
public void onMessage(Message msg) {
    String message;
    if (msg instanceof TextMessage) {
        message = ((TextMessage) msg).getText();
        LOG.info("In here START " +  message) ;
        Thread.sleep(60000); //I crash my app while thread is sleeping here
        LOG.info("In here END " +  msg.getJMSDestination() ) ;
        
    }
public class SolaceConfig {

    @Bean("solaceJndiTemplate")
    public JndiTemplate solaceJndiTemplate() {
        JndiTemplate solaceJndiTemplate = new JndiTemplate();
    
           // setting user name /password ommitted for brevity

            solaceJndiTemplate.setEnvironment(properties);
            
        
        return solaceJndiTemplate;
    }   
    
    @Bean
    public JndiObjectFactoryBean solaceConnectionFactory(){
        
        JndiObjectFactoryBean solaceConnectionFactory = new JndiObjectFactoryBean();
        solaceConnectionFactory.setJndiTemplate(solaceJndiTemplate());
        solaceConnectionFactory.setJndiName(getJndiName());
        return solaceConnectionFactory;
    }

    @Primary
    @Bean
    public CachingConnectionFactory solaceCachedConnectionFactory(){
        CachingConnectionFactory solaceCachedConnectionFactory = new CachingConnectionFactory();
        solaceCachedConnectionFactory.setTargetConnectionFactory((ConnectionFactory)solaceConnectionFactory().getObject());
        solaceCachedConnectionFactory.setSessionCacheSize(10);
        return solaceCachedConnectionFactory;
    }

    @Bean
    public JmsTemplate jmsTemplate() {
        JmsTemplate jmsTemplate = new JmsTemplate(solaceCachedConnectionFactory());
        jmsTemplate.setDeliveryPersistent(true);
        jmsTemplate.setExplicitQosEnabled(true);
        return jmsTemplate;
    }

    @Bean
    public DefaultJmsListenerContainerFactory jmsContainer() {
        DefaultJmsListenerContainerFactory container = new DefaultJmsListenerContainerFactory();
        container.setConnectionFactory(solaceCachedConnectionFactory());
    //container.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
        return container;
    }

Solution

  • When using the DMLC, you should enable transactions (set sessionTransacted) so that the acknowledgment is rolled back.

    Otherwise, use a SimpleMessageListenerContainer instead.

    See the javadocs https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jms/listener/DefaultMessageListenerContainer.html

    It is strongly recommended to either set "sessionTransacted" to "true" or specify an external "transactionManager". See the AbstractMessageListenerContainer javadoc for details on acknowledge modes and native transaction options, as well as the AbstractPollingMessageListenerContainer javadoc for details on configuring an external transaction manager. Note that for the default "AUTO_ACKNOWLEDGE" mode, this container applies automatic message acknowledgment before listener execution, with no redelivery in case of an exception.