1 2 3 4 Previous Next 52 Replies Latest reply on Apr 7, 2008 6:29 AM by timfox Go to original post
      • 30. Re: Bug in transactional delivery in an MDB
        clebert.suconic

        I just realized http://jira.jboss.org/jira/browse/JBMESSAGING-410 was rejected. I thought it was fixed.

        I opened a new issue http://jira.jboss.org/jira/browse/JBMESSAGING-946 linking both of them.

        I'm committing a proposed fix. Basically I'm doing this test within SessionAspect:

        public Object handleSend(Invocation invocation) throws Throwable
         {
         SessionState state = getState(invocation);
         Object txID = state.getCurrentTxId();
        
         // (notice that txID is never null as SessionState will aways create it) (Post edited this line)
        
         if (state.isXA() && !(txID instanceof LocalTx) || (!state.isXA() && state.isTransacted()))
        



        Both my integration tests and TCK worked with this change. I will run the testsuite now.

        For fixing this I tried also changing SessionState constructor, to not create the local transaction if XA (as it was the original version as I could see on history)... but then the txID existence was tide up with other sanity checks and I got exceptions in other places. I tried to fix those and some testcases were failing. The fix above was the less invasive as possible (without requiring much refactoring).

        • 31. Re: Bug in transactional delivery in an MDB
          timfox

          The problem with 410 is it is inconsistent with transactional delivery in an MDB.

          If an XASession not enlisted in a transaction acts as non transacted, then you end up with transacted delivery of messages in an MDB failing.

          This is because the message is delivered and sometime *after* the XASession is enlisted in the tx.

          This is why we fall back to being transacted, otherwise messages we get immediately acked from transacted MDBs.

          Your "fix" reverses this behaviour for sends but not receives.

          • 32. Re: Bug in transactional delivery in an MDB
            timfox

            I suspect your fix will cause the following use case to fail:

            Send message to another queue from inside the onMessage method of an MDB.

            Immediately after sending throw a RuntimeException.

            Make sure onMessage executes transactionally.

            This should cause the tx to rollback and the message shouldn't be sent.

            What you'll probably find with your latest change is that the message gets sent even though the tx rolls back.

            • 33. Re: Bug in transactional delivery in an MDB
              timfox

              Pls Ignore my previous comment - I don't think it is correct.

              So what we end up with is the following behaviour:

              An XASession that is not enlisted in a global tx behaves:

              a) As a local transacted session for any messages *consumed*, this is so we can consume messages in an MDB in the context of a global tx (This is the old chestnut where the container can't enlist the session in the global tx until after the message has been consumed from the provider using ASF).

              b) As a non transacted session for any messages *sent*.

              So as you can see it will behave differently for any messages sent as opposed to consumed.

              • 34. Re: Bug in transactional delivery in an MDB
                timfox

                I have added tests in XATest to test our new expected behaviour.

                Some of these are reconsituted from the old graveyard tests

                • 35. Re: Bug in transactional delivery in an MDB
                  timfox

                  And XATest (at least) is now passing 100%

                  • 36. Re: Bug in transactional delivery in an MDB
                    clebert.suconic

                    I have executed the whole testsuite and I didn't see any failures related to transactional behaviors.

                    And regarding to ACKs, I believe we should treat ACK on XA the as nonTransacted/AutoAck.

                    For this, we would have to probably change SessionAspect::handlePreDeliver:

                     if (ackMode == Session.CLIENT_ACKNOWLEDGE)
                     {
                     // We collect acknowledgments in the list
                    
                     if (trace) { log.trace(this + " added to CLIENT_ACKNOWLEDGE list delivery " + info); }
                    
                     // Sanity check
                     if (info.getConnectionConsumerSession() != null)
                     {
                     throw new IllegalStateException(
                     "CLIENT_ACKNOWLEDGE cannot be used with a connection consumer");
                     }
                    
                     state.getClientAckList().add(info);
                     }
                     else if (ackMode == Session.AUTO_ACKNOWLEDGE ||
                     (state.isXA() && (state.getCurrentTxId() instanceof LocalTx)))
                     {
                    


                    and postDeliver:

                    public Object handlePostDeliver(Invocation invocation) throws Throwable
                     {
                     MethodInvocation mi = (MethodInvocation)invocation;
                     SessionState state = getState(invocation);
                    
                     int ackMode = state.getAcknowledgeMode();
                    
                     // if XA and there is no transaction enlisted on XA we will act as AutoAcknowledge
                     if (ackMode == Session.AUTO_ACKNOWLEDGE ||
                     (state.isXA() && state.getCurrentTxId() instanceof LocalTx))
                     {
                    



                    What is weird though is, I have written an integration testcase, where a message was received inside an EJB, and it looked like the message was ACKed even though I didn't have a transaction to commit it. I know Tim tried to explain me how this would work but now I got confused.

                    • 37. Re: Bug in transactional delivery in an MDB
                      timfox

                       

                      "clebert.suconic@jboss.com" wrote:

                      And regarding to ACKs, I believe we should treat ACK on XA the as nonTransacted/AutoAck.


                      Well, this is exactly what I have talked about several times and exactly why this thread was originally started.

                      Let me summarise:

                      There is a design flaw in the old ASF stuff such that the message is received from the underlying JMS provider *before* it is passed onto the StdServerSession which then, if appropriate, starts a tx and enlists the session.

                      Therefore when the message is consumed it is an XA session but is not in a transaction.

                      This is why we fallback the behaviour of an XASession that is not enlisted to a local tx and when it is enlisted we convert the work done into the global tx.

                      Originally we were auto_acking, hence messages received in transacted MDBs aren't received in the context of the tx. Ooops. This was the original bug that triggered the thread.

                      This problem is explained in detail in Mark Little's transaction book. It is not a problem specific to JBoss. I believe that solving this problem was one of the motivations for JCA1.5 message inflow.

                      • 38. Re: Bug in transactional delivery in an MDB
                        timfox

                        This is what we need to work out:

                        "adrian@jboss.org" wrote:


                        The JBossMQ behaviour is to assume that an XASession behaves like
                        AUTO_ACKNOWLEDGE when the XASession is not enlisted in a JTA transaction.
                        (Some JMS implements throw an exception in this case).

                        There is one exception to this. When the XASession is being used as part of
                        a ServerSessionPool, the semantics need to be receive then enlist.
                        So for this, the XASession behaves like there is a transaction, it will be told
                        later what XID to use for the 2PC protocol.


                        The question I still don't understand is how does the XASession know it is being used as part of the ServerSessionPool, so it can apply the different behaviour.

                        Looking through the code, I can't for the life of me work out how this information is passed from the ServerSessionPool to the session.

                        Can anyone (Adrian? Weston?) shed any light on this. This is becoming a bit of a blocker for us.

                        So to recap:

                        We have an XASession that is not enlisted in a global tx.

                        In the case that XASession is created using a ServerSessionPool we want it to fall back to local transaction semantics. For all other cases we want it to have AUTO_ACK semantics.

                        How does the session know which semantics to follow in the absence of a global tx?

                        • 39. Re: Bug in transactional delivery in an MDB
                          weston.price

                          Adrian's comment are out of date. We always begin a transaction prior to the receive to support JMS providers where this is required (aka WebSpehreMQ). There was code at one point to be able to toggle this behavior on and off, but it has since been removed in the JCA adapter.


                          We have an XASession that is not enlisted in a global tx.


                          That's fine the underlying resource will simply not be enlisted. For inbound this is up to the JCA/JMS adapter which is described below.



                          In the case that XASession is created using a ServerSessionPool we want it to fall back to local transaction semantics. For all other cases we want it to have AUTO_ACK semantics.


                          I am not sure what you are asking. In the case of inbound messages the transaction behavior depends on the transaction attributes of the MDB. For CMT we use XA, for BMT and CMT/NotSupported we use local JMS transactions to support redelivery in the event of a RuntimeException.








                          • 40. Re: Bug in transactional delivery in an MDB
                            timfox

                            The problem we have is this:

                            In the case of an MDB, the message is consumed from the underlying JMS provider *before* the MDB container has a chance to enlist the session in a global tx (this is the old design problem with ASF).

                            So the XASession needs to behave like a local transacted session if it is not enlisted in a global tx, otherwise, if it behaved like auto ack it would get acked immediately, then, some time later the onMessage gets called which is implemented by the StdServerSession which enlists the XASession in the global tx, at which point we _convert_ the work done previously in the local tx into the global tx.

                            So this is fine for the MDB case - the case where the session was created by the StdServerSessionPool.

                            However if the XASession wasn't created via the SessionPool - i.e. it's not a session for a transacted MDB, then we don't want it to fall back to behaving like a local transacted session, we want it to behave like auto_ack.

                            E.g. If in a method of an EJB, I use the JCA MCF to create a connection, session, then send a message, but no global tx is present, we want the message to be sent immediately - i.e. we want the XASession to behave non transactionally.

                            Also, in the same EJB method, we use the JCA MCF to create a connection, session, consumer, consume a message, then we want that message to get acked - i.e. the session to behave non transactionally.

                            This is the behaviour JBoss MQ has.

                            So, basicaly the session needs to behave differently depending on whether it was created via a session pool or not. But the problem is how to signal that to the session - I can't see how to do that.

                            • 41. Re: Bug in transactional delivery in an MDB
                              clebert.suconic

                               

                              "Tim Fox" wrote:
                              But the problem is how to signal that to the session - I can't see how to do that.


                              Couldn't we use (sessionState.getListener() instanceof ServerSession) to determine that?

                              From my understand from what I just read about JMS Spec Secion 8.6 on Application Server Facilities a ServerSession would be used on that context.

                              • 42. Re: Bug in transactional delivery in an MDB
                                clebert.suconic

                                I have tested the instanceof ServerSession, and an integration tests where I had a redeliver test (when an exception happened) was failing before the change, and passed after the change.

                                • 43. Re: Bug in transactional delivery in an MDB
                                  timfox

                                   

                                  "clebert.suconic@jboss.com" wrote:
                                  "Tim Fox" wrote:
                                  But the problem is how to signal that to the session - I can't see how to do that.


                                  Couldn't we use (sessionState.getListener() instanceof ServerSession) to determine that?

                                  From my understand from what I just read about JMS Spec Secion 8.6 on Application Server Facilities a ServerSession would be used on that context.


                                  I don't think so. Implementing MessageListener on the ServerSession is just how JBoss implements ASF, but it's an implementation detail - not mandated by the spec.

                                  • 44. Re: Bug in transactional delivery in an MDB
                                    weston.price

                                    Can we have a call about this?