MQ

 View Only
  • 1.  Best practices with JMS and backout queue

    IBM Champion
    Posted Wed March 09, 2022 10:10 AM
    Some of our Spring-JMS developers need to consume from a queue using transactions with a backout queue pattern.  The goal is that after a message is rolled back a certain number of times, then it will be automatically moved to the backout queue.  We have the target and backout queues defined as follows on the server:

    DEFINE QLOCAL('MYQUEUE') CLWLUSEQ(ANY) CLUSTER('MYCLUS') DEFBIND(NOTFIXED) BOQNAME('MYQUEUE.BO') BOTHRESH(3) REPLACE
    DEFINE QLOCAL('MYQUEUE.BO') CLWLUSEQ(ANY) CLUSTER('MYCLUS') DEFBIND(NOTFIXED) REPLACE

    We've found several JMS examples using MQ transactions with commit and rollback.  There seem to be multiple ways to code this in JMS.  What we're finding is that some will automatically move the message to the backout queue once the threshold is exceeded and others do not.  For example, this example does automatically move the message:
    @SpringBootApplication
    @RestController
    @EnableJms
    @EnableTransactionManagement
    public class MqTransactApplication {
    
    ... 
    
    private static JmsTemplate jmsTemplate;
    private static JmsTransactionManager jmsTransaction;
    private TransactionStatus status = null;
    
    public static void main(String[] args) {
    	ConfigurableApplicationContext context = SpringApplication.run(MqTransactApplication.class, args);
    	jmsTemplate = context.getBean(JmsTemplate.class);
    	jmsTransaction = new JmsTransactionManager();
    	jmsTransaction.setConnectionFactory(jmsTemplate.getConnectionFactory());
    }
    
    @PostMapping(value = "recv", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
    		MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<RecvResponse> recv(@RequestBody RecvRequest request) {
    	try {
    		TransactionStatus status = jmsTransaction.getTransaction(null);
    		String msg = jmsTemplate.receiveAndConvert(QUEUE_NAME).toString();
    		boolean commit = this.handleMessage(msg);
    		if (commit) {
    			jmsTransaction.commit(status);
    		} else {
    			jmsTransaction.rollback(status);
    		}
    		return ResponseEntity.created(null).body(new RecvResponse("Success", msg));
    	} catch (JmsException ex) {
    		ex.printStackTrace();
    		return ResponseEntity.created(null).body(new RecvResponse("Fail"));
    	}
    }
    
    }

    However, this approach does not.  The code continues to receive the same message after rollback even though the backout count is greater than than the threshold. 

    @Component
    public class Responder implements SessionAwareMessageListener {
    
      @JmsListener(destination = Requester.qName)
      @Transactional(rollbackFor = Exception.class)
      public void onMessage(Message msg, Session session) throws JMSException {
        String text;
    
        if (msg instanceof TextMessage) {
          text = ((TextMessage) msg).getText();
        }
        else {
          text = msg.toString();
        }
    
        final String msgID = msg.getJMSMessageID();
    
        MessageProducer replyDest = session.createProducer(msg.getJMSReplyTo());
        TextMessage replyMsg = session.createTextMessage("Replying to " + text);
        replyMsg.setJMSCorrelationID(msgID);
        replyDest.send(replyMsg);
    
        if (!msg.getJMSRedelivered()) {
          System.out.println("Doing a rollback");
          session.rollback();
          /*throw new JMSException("Instead of rollback?");*/
        }
        else {
          System.out.println("Doing a commit");
          session.commit();
        }
      }
    }​

    Is there something missing from the above example? 

    More importantly, is there a best practice or preferred way to consume messages with JMS when using a backout queue?  I've seen other references to MessageConsumer and ConnectionConsumer classes in this context (neither of which we have tried, yet).

    Thanks

    ------------------------------
    Jim Creasman
    ------------------------------



  • 2.  RE: Best practices with JMS and backout queue

    Posted Mon March 14, 2022 09:04 AM
    Hi
    I did get some good answers in this discussion about backout-queues thanks to @Morag Hughson. Where I apparently had misunderstood the meaning of backout-queues. Maybe it will answer some of your thoughts https://community.ibm.com/community/user/integration/communities/community-home/digestviewer/viewthread?GroupId=379&MessageKey=622b6220-10d1-493a-822c-4f9c02da90a9&CommunityKey=183ec850-4947-49c8-9a2e-8e7c7fc46c64&ReturnUrl=%2fcommunity%2fuser%2fintegration%2fcommunities%2fcommunity-home%2fdigestviewer%3fCommunityKey%3d183ec850-4947-49c8-9a2e-8e7c7fc46c64

    Regards



    ------------------------------
    Daniel Nordkvist
    ------------------------------



  • 3.  RE: Best practices with JMS and backout queue

    IBM Champion
    Posted Wed March 16, 2022 03:40 PM
    I agree.  Morag did a good job of summarizing how poison messages and automatic backout works.  However, this isn't quite our scenario.  We don't have a poison message in that the client is unable to process it.  Our client is able to perform a rollback on the transaction.  It's just that the backout continues to increase and the message is never moved to the backout queue.  The problem is definitely on the JMS side of things and not with MQ, which is performing as expected.

    ------------------------------
    Jim Creasman
    ------------------------------



  • 4.  RE: Best practices with JMS and backout queue

    Posted Tue March 15, 2022 04:35 AM
    Hi, Once the threshold is reached and nothing else is holding the message, then the message should be put on the BOQ,  You may want to try session.recover() afterwards to start fresh with the session, if it issue being by the session.

    Brian

    ------------------------------
    Brian S Paskin
    Sr. Web Engineer
    IBM Tech Garage
    ------------------------------



  • 5.  RE: Best practices with JMS and backout queue

    IBM Champion
    Posted Wed March 16, 2022 03:41 PM
    Thanks for the suggestion (and affirmation).  I'll pass this along to our client developer.

    ------------------------------
    Jim Creasman
    ------------------------------