1 Reply Latest reply on Jul 21, 2007 6:15 AM by ojacobson

    Configuring retry behaviour for an MDB

    ojacobson

      Good afternoon.

      I'm working my way towards understanding JMS and MDBs and I've encountered a roadblock.

      I have a very simple MDB which accepts one message out of X (it cheats on the EJB spect and keeps a per-instance "how many messages have I recieved" count) and "rejects" the rest with context.setRollbackOnly(). When X is large enough, JBoss gives up on re-sending the message before the next "accept message" state comes up and drops the message in the DLQ.

      What I want to do is instruct JBoss to retry the message indefinitely, accepting the risk of a poison message blocking any further messages from being processed. If possible I'd also like the retries to be delayed a few seconds, rather than being re-delivered immediately after transaction rollback.

      What configuration changes do I need to make to have at least one of those effects?

      I have the following dead-simple MDB implementation:

      package xxx;
      
      import javax.annotation.Resource;
      import javax.ejb.ActivationConfigProperty;
      import javax.ejb.MessageDriven;
      import javax.ejb.MessageDrivenContext;
      import javax.ejb.TransactionAttribute;
      import javax.ejb.TransactionAttributeType;
      import javax.jms.JMSException;
      import javax.jms.Message;
      import javax.jms.MessageListener;
      import javax.jms.TextMessage;
      
      import org.apache.log4j.Logger;
      
      @MessageDriven(activationConfig = {
       @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
       @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/MDBDemo") })
      public class Receiver implements MessageListener {
       private int count = 0;
       private static final int MODULUS = 100;
      
       private static final Logger log = Logger.getLogger(Receiver.class);
      
       @Resource
       private MessageDrivenContext context;
      
       @TransactionAttribute(TransactionAttributeType.REQUIRED)
       public void onMessage(Message message) {
       log.info("Recieve " + count + " of " + MODULUS);
       boolean accept = count == 0;
      
       count = (count + 1) % MODULUS;
      
       if (accept)
       try {
       log.info("Accepted message: "
       + ((TextMessage) message).getText());
       } catch (JMSException e) {
       log.error("JMX Exception", e);
       context.setRollbackOnly();
       }
       else {
       log.info("Rejecting message.");
       context.setRollbackOnly();
       }
       }
      }


      There are no deployment descriptors in the ejb-jar file (neither ejb-jar.xml nor jboss.xml).

      There is no MBean descriptor for the queue/MDBDemo Queue.

      The message-driven-bean invoker proxy binding in standardjboss.xml has been edited to have MaxTimesRedelivered = 3 instead of the default of 10; this does not appear to have any effect on how many times MDB delivery is attempted before JBoss gives up and sends the message to the DLQ. (Related question: will removing the DLQConfig element entirely accomplish what I want?)

      All of this is running under JBoss 4.0.4.GA.

        • 1. Re: Configuring retry behaviour for an MDB
          ojacobson

          I've solved this myself; my solution is documented below.

          1. For unlimited re-attempts at delivering the message, I used the ActivationConfigProperty annotations to set the "useDLQ" property of the MDB activation to "false".

          2. For delayed re-attempts, configure the queue as an MBean explicity with RedeliveryDelay set to the number of milliseconds (minimum) between successive delivery attempts at the same message. This is a PER-MESSAGE delay; four messages being redelivered will cause delivery attempts to arrive 4x as fast. This was acceptable for my use case.