8 Replies Latest reply on Nov 24, 2008 10:05 AM by orankelly

    Can only send one message in XA transaction

    orankelly

      I'm having a problem with Jboss 4.2.3.GA + Jboss messaging 1.4.0SP3. I am sending multiple messages within a JTA transaction. However, at transaction commit time, only the first message sent is actually delivered to the destination (a topic).

      My app is Spring-based and I normally use the JmsTemplate support but to try to eliminate the possibility that Spring was the problem, I threw together a simple bean that did the following in a method annotated with Spring's @Transactional notation with propagation REQUIRED:

      InitialContext ic = new InitialContext();
      Context context = (Context) ic.lookup("java:comp/env");
      Destination dest = (Destination) context.lookup("jms/MyTopic");
      // jms/ConnectionFactory is tied to java:/JmsXA
      ConnectionFactory cf = (ConnectionFactory) context.lookup("jms/ConnectionFactory");
      Connection conn = cf.createConnection();
      Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
      MessageProducer producer = s.createProducer(dest);
      TextMessage m = s.createTextMessage("Message 1");
      producer.send(m);
      m = s.createTextMessage("Message 2");
      producer.send(m);
      m = s.createTextMessage("Message 3");
      producer.send(m);
      s.close();
      conn.close();
      


      Upon invoking this, only one message gets delivered to the topic after the method returns (and therefore the transaction commits). This confuses me no end. If there was a problem in the method that caused a rollback, no messages would be delivered, right? Likewise if there was a problem during the actual commit.

      If I change over to using the non-XA "ConnectionFactory" and invoke the same code, all three of the messages get delivered.

      Anyone any hints as to why this would be?

      (I have configured jboss-messaging as per the instructions in its documentation. I am also using mysql as the persistence provider rather than the default hsqldb. My default engine is InnoDB so the JBM_ tables are all using that engine and my tx isolation level is READ_COMMITTED.)


        • 1. Re: Can only send one message in XA transaction
          timfox

          Probably spring isn't enlisting the JBM xa resource properly with the global tx.

          But I can't really comment on the internal workings of Spring. You're best best is to debug the Spring code, or ask a Spring expert.

          • 2. Re: Can only send one message in XA transaction
            gaohoward

            Can you also give the client code that consume the messages here? It may help to find the problem.

            • 3. Re: Can only send one message in XA transaction
              orankelly

               

              "timfox" wrote:
              Probably spring isn't enlisting the JBM xa resource properly with the global tx.

              But I can't really comment on the internal workings of Spring. You're best best is to debug the Spring code, or ask a Spring expert.


              Ok so, just to be sure, I have discarded the @Transactional annotations from the bean and modified the example above to manually get the UserTransaction, begin and commit that transaction around the sending of the messages and I get exactly the same behaviour - only one message is actually delivered, the first one that I "send". At this point, Spring isn't involved in the sending side of the transaction at all (well, ok, apart from wrapping a JDK proxy around my bean...see my note on deployment below).

              InitialContext ic = new InitialContext();
              tx = (UserTransaction) ic.lookup("java:comp/UserTransaction");
              tx.begin();
              Context context = (Context) ic.lookup("java:comp/env");
              Destination dest = (Destination) context.lookup("jms/MyTopic");
              // jms/ConnectionFactory is tied to java:/JmsXA
              ConnectionFactory cf = (ConnectionFactory) context.lookup("jms/ConnectionFactory");
              Connection conn = cf.createConnection();
              Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
              MessageProducer producer = s.createProducer(dest);
              TextMessage m = s.createTextMessage("Message 1");
              producer.send(m);
              m = s.createTextMessage("Message 2");
              producer.send(m);
              m = s.createTextMessage("Message 3");
              producer.send(m);
              s.close();
              conn.close();
              Thread.sleep(7000);
              tx.commit();
              


              To clarify how I'm invoking the above code: I am still deploying the bean in a spring app context but I am exporting it as an MBean and then invoking an operation using jboss's jmx console. In this most recent effort, I turned on debug logging for spring's tx framework and have confirmed that it was not attempting to do anything transactional around my test (at debug level it is pretty verbose about what it's up to..)


              • 4. Re: Can only send one message in XA transaction
                timfox

                Are you doing this inside the app server?

                You can only use the JMS JCA resource adapter (JmsXA) in a managed environment...

                • 5. Re: Can only send one message in XA transaction
                  orankelly

                   

                  "gaohoward" wrote:
                  Can you also give the client code that consume the messages here? It may help to find the problem.


                  Sure, though it's very simple stuff:
                  public class SimpleListener implements javax.jms.MessageListener {
                   private static final Logger LOG = LoggerFactory.getLogger(SimpleListener.class);
                  
                   public void onMessage(Message message) {
                   try {
                   if (message instanceof TextMessage) {
                   LOG.info("TextMessage received: {}", ((TextMessage) message).getText());
                   } else {
                   LOG.info("{} received: {}", message.getClass().getSimpleName(), message);
                   }
                   } catch (Exception x) {
                   LOG.error("", x);
                   }
                   }
                  }
                  


                  The output to my logs after invoking the sender code seen in earlier posts:
                  2008-11-24 12:19:29,828 INFO [com.pbm.sms.event.SimpleListener] (WorkManager(2)-36) TextMessage received: Message 1
                  



                  This is tied in to the topic using Spring's DefaultMessageListenerContainer (referencing the java:/JmsXA connection factory and JTA transaction manager). After posting this I will go away and write a plain MDB in order to further remove Spring from the equation but I'm not expecting much of a change in behaviour (famous last words...).


                  • 6. Re: Can only send one message in XA transaction
                    timfox

                     

                    "orankelly" wrote:
                    After posting this I will go away and write a plain MDB in order to further remove Spring from the equation


                    Yes please let's take Spring out of the equation. If you can demonstrate an issue using an MDB we can investigate further...

                    • 7. Re: Can only send one message in XA transaction
                      orankelly

                       

                      "timfox" wrote:
                      Are you doing this inside the app server?

                      You can only use the JMS JCA resource adapter (JmsXA) in a managed environment...


                      Yep, inside a running jboss-4.2.3.GA instance ("default" configuration, customised with jboss-messaging-1.4.0, 'jgroups.jar' copied over from the 'all' config as a jbm dependency but I'm not using a clustered config (yet)).

                      • 8. Re: Can only send one message in XA transaction
                        orankelly

                         

                        "timfox" wrote:
                        Yes please let's take Spring out of the equation. If you can demonstrate an issue using an MDB we can investigate further...


                        Famous last words indeed.

                        The root cause is some oddness with Spring's listener interacting with the tx manager. So the sending side was working but the listener was not getting all of the messages. As yet I have no idea why but if I stop populating the DefaultMessageListenerContainer's transactionManager property, all the messages are received.

                        When I deployed the simple MDB (identical code to that SimpleListener I posted earlier), all the messages were received correctly. I noticed some very odd behaviour with this new conf though, whereby my original listener, which I still had deployed, occasionally saw more than one message delivered - but never got all 3 and usually only got the first one.

                        Anyhoo - not a JBM issue!