4 Replies Latest reply on Mar 23, 2009 6:30 PM by Azda L

    MDB 'at most, once' delivery (Ack before onMessage)

    Azda L Newbie

      Is there any way to set up the MDB container to send an acknowledgment before it calls onMessage? (I'm currently using EJB 3, but I don't think this is an EJB 3 specific question. The app server is 5.0.1GA)

      This seems like a fairly straight forward delivery pattern (guarantee the message was received, but not necessarily that any work was completed. a.k.a 'at most, once'). I'm having problems figuring out if JEE supports this, or I'm just missing the right combination of settings.

      Here are my requirements:
      1.) I don't need a transaction
      2.) A message should be processed 'at most, once' (it doesn't matter if the MDB acks and crashes before calling onMessage, thus loosing the message, as long as no duplicates are delivered)

      I've set up:
      TransactionManagementType.BEAN, TransactionAttributeType.NOT_SUPPORTED for onMessage, acknowledgeMode=Auto-acknowledge,
      as well as MaxDeliveryAttempts=1 on the Queue

      I read somewhere that this configuration would get me what I want (maybe for another app server?). It doesn't.

      1.) Ack isn't until onMessage completes
      2.) If the app server crashes (I simulated by just killing the JVM), when it comes back up, the messages that were processing when the crash occurred, get re-delivered (even though I have MaxDeliveryAttempts at 1)!

      The behavior of 2 is what I would expect with acknowledgeMode=Dups-ok-acknowledge. I've read that this mode has the feature of not waiting till onMessage finishes to ack, but you can't guarantee when. So you have to deal with the possibility of duplicates.

      In Summary: I'd rather not have to deal with detecting duplicates, and it seems easy enough to do, if the container would just ack before onMessage. Is this possible, or am I just wishfully thinking?


        • 1. Re: MDB 'at most, once' delivery (Ack before onMessage)
          Santiago Erquicia Newbie

          Can't you set up the queue so it only attempts to deliver it once.

          In JBoss Messaging it would be something like:

           <mbean code="org.jboss.jms.server.destination.QueueService"
           <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
           <attribute name="MaxDeliveryAttempts">1</attribute>

          If the delivery isn't successful, the message will end up in the dead letter queue.

          Hope it helps ;)

          • 2. Re: MDB 'at most, once' delivery (Ack before onMessage)
            Azda L Newbie

            Yes, that's currently the exact configuration of my queue. There are two things I would like to solve:

            1.) The processing in my MDB can take a long time. During this time, the provider is holding the unacknowledged message. This probably isn't a big deal, but in my case it doesn't have to, so if there is anything I can do to alleviate that behavior, I would like to do it.

            2.) This is the bigger issue, because it is the exact opposite of what I need to happen, and kind of unexpected. In my test, I put a sleep statement in my MDB to simulate long processing. I send five messages to the queue, so five MDB instances start and go to sleep. At that point I crash the server. When the server starts back up, those messages get delivered again (and the MDBs go back to sleep). If that had been my actual application logic, it would be duplicating events, which would be bad.

            If this is the behavior, I'll have to check for duplicates anyway, and might as well use Dups-ok-acknowledge.

            One thing I didn't check, which I will check tomorrow, is if the redelivered flag is set the second time around. Since I have MaxDeliveryAttempts set to 1, I would have expected it to go to the DLQ in that case.

            • 3. Re: MDB 'at most, once' delivery (Ack before onMessage)
              Azda L Newbie

              Ok, I checked and JMSRedelivered is set to false.

              After pouring over the specs, I think I've corrected some of my misunderstandings.

              According to the JMS spec, with AUTO_ACKNOWLEDGE, the acknowledgment occurs after receive or onMessage. Since the MDB is using the MessageListener interface, I would assume the receipt must happen after onMessage. I guess what I'm really after is CLIENT_ACKNOWLEDGE, which the EJB spec does not support. (Unfortunate, because I'll just have to waste time doing all the JMS and thread pool programming to simulate an EJB container with this functionality. That, or do duplicate checking)

              All that said, I still think there is a bug with AUTO_ACKNOWLEDGE. The JMS spec states that the client should be prepared for re-delivery of the last consumed message, for this very reason. (Processing occurring in onMessage, and JMS crashing before receipt). It states that in this situation, JMSRedelivered should be set to true. (Which it is not in my example). I'll have to do more testing, and take my questions to the JMS forum.