0

I am trying to configure JmsTemplate in transactional manner, so when error occures durring the processing or writing, i want the messages to be visible in the queue again. I have the below configurations which seems to works fine when error occures i.e. if error is thrown durring the writing or processing, the messages are "sent" back to the queue. But the problem is when everything is OK (i.e. no errors are thrown), then only one message is consumed, processed and dequeued. So if i have 10 messages in the queue, only one is dequeued and the job is marked as COMPLETED. If i configure JmsTemplate with

jmsTemplate.setSessionTransacted(false);

I have all messages consumed, processed and written, but of course I am loosing the transactional manner. The question is how to get all mesasges transactionaly consumed and processed and written?

I have the following JmsTemplate configuration

@Bean
public JmsTemplate jmsTemplate() {
    JmsTemplate jmsTemplate = new JmsTemplate(activeMQConnectionFactory());
    jmsTemplate.setDefaultDestinationName(applicationProperties.getQueue());
    jmsTemplate.setDefaultDestination(queue());
    jmsTemplate.setReceiveTimeout(applicationProperties.getReceiveTimeout());
    jmsTemplate.setSessionTransacted(true);
    jmsTemplate.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
    return jmsTemplate;
}

which is passed to my JmsItemReader

@Bean
public ItemReader<MyPojoClass> myJmsItemReader() throws Exception {

    JmsItemReader<MyPojoClass> myJmsItemReader= new JmsItemReader<>();
    myJmsItemReader.setItemType(MyPojoClass.class);
    myJmsItemReader.setJmsTemplate(jmsTemplate);
    myJmsItemReader.afterPropertiesSet();
    return myJmsItemReader;

}

and below is my tasklet configuration

@Bean(name = "receiveProcessAndWrite")
public TaskletStep receiveProcessAndWrite() throws Exception {

    return this.stepBuilderFactory.get("receiveProcessAndWrite")
            .transactionManager(transactionManager)
            .<MyPojoClass, MyPojoClass>chunk(1000)
            .readerIsTransactionalQueue()
            .reader(myJmsItemReader())
            .processor(myprocessor())
            .writer(updateStatusInDBandWrite())
            .listener(new ChunkCountListener())
            .build();

}
evilsoldier
  • 161
  • 12
  • if SessionTransacted=false, and 10 messages are there, how many job comepletions happen?? Only 1 or 10? – Anand Varkey Philips Aug 29 '18 at 13:00
  • Only one. All messages are processed in only one Job execution. – evilsoldier Aug 29 '18 at 13:01
  • I'm experiencing the same result with ActiveMQ (I guess you're also using ActiveMQ from the connection factory method name `activeMQConnectionFactory `). Here is the project I used to test the use case: https://github.com/benas/demo-batch-jms. I confirm, when the session is transacted, the reader reads (receives) the first item and then a timeout happens and the reader returns null, yielding a chunk with only one item. Probably this is related to the JMS provider (ActiveMQ). I need to test with another provider and see if the same phenomenon happens. – Mahmoud Ben Hassine Aug 30 '18 at 11:37
  • Correct, i am using org.apache.activemq.ActiveMQConnectionFactory – evilsoldier Aug 30 '18 at 12:16
  • I was able to isolate the issue. It is not related to the jms provider. The timeout happens even if we use the jms template without a Spring Batch job (see https://github.com/benas/demo-batch-jms/commit/bdafa43b23811bd370bdaded95f4ad48c0ce394d). This is related to the transaction manager used which is not a JTA transaction manager. The use case has two transactional resources (jms queue and jdbc datasource) and hence you need to configure a JTA transaction manager (XA aware) to coordinate jms and database transactions. Hope this helps. – Mahmoud Ben Hassine Sep 03 '18 at 11:07
  • FTR, I moved the code of the demo here: https://github.com/benas/sandbox/tree/master/so52077945 – Mahmoud Ben Hassine Mar 19 '19 at 19:02

0 Answers0