5 Replies Latest reply on Aug 29, 2006 10:14 AM by amadeuz

    Synchronizing MessageDrivenContext

    amadeuz

      I have an issue of JBoss terminating (rolling back) the context of the message driven bean when large amount of MDB instances are actively processing the message and gives me the following exceptions:

      Caused by: org.hibernate.TransactionException: could not register synchronization with JTA TransactionManager
       at org.hibernate.jdbc.JDBCContext.registerSynchronizationIfPossible(JDBCContext.java:160)
       at org.hibernate.jdbc.JDBCContext.<init>(JDBCContext.java:79)
       at org.hibernate.impl.SessionImpl.<init>(SessionImpl.java:266)
       at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:436)
       at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:460)
       at org.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:468)
       at com.quinstreet.dms.leadprocessor.util.hibernate.DbConfig.getSession(DbConfig.java:176)
       ... 30 more
      Caused by: javax.transaction.RollbackException: Already marked for rollback
       at org.jboss.tm.TransactionImpl.registerSynchronization(TransactionImpl.java:717)
       at org.hibernate.jdbc.JDBCContext.registerSynchronizationIfPossible(JDBCContext.java:149)
       ... 36 more


      This is due to context being rolled back in the middle of some processing and the system attempt to obtain new connection. I'm using Hibernate to query and in certain case update multiple instances of DBs. I have tried using XA 3 Phase commit JDBC driver but didn't work for me and I decided to try to use the sync block in my code:

      // Make sure no body modify the context of this process during processing
       synchronized (context) {
       try {
       if (!context.getRollbackOnly()) {
       Processor.process(message, cacheName);
       } else {
       return;
       }
       } catch (Exception e) {
       String exceptionMsg = new StringBuilder().append("Exception occured while processing message: ")
       .append(message).toString();
       ExceptionHandler.handle(e, exceptionMsg, MessageProcessorHelper.getMessageInfo(message));
       return;
       }
       }


      I did this because there are multiple complex sequences of queries that I perform within Processor.process() that makes it hard to trace whether context has been rolled back before obtaining connections (I may be wrong but I will have to pass MessageDrivenContext instance to all of the connection obtaining class - I'm not using Spring).

      Now the sync block works great, until a restart is initiated. When some messages are being processed while a server restart is initiated, certain things are undeployed (connections, ejbs, etc) and it looks like my MDB is waiting for the undeployed piece and hangs while the restart is waiting for the context to be freed which causes me to have the following warnings:

      [org.jboss.ejb.plugins.AbstractInstanceCache] Unable to passivate due to ctx lock, id=11674561


      This is BAD because it prevents JBoss to shutdown gracefully, I would have to kill the process to restart it.

      I'm aware that this might not be the best solutions so please let me know if there's anyway I can get around the above issues. Any constructive response will be highly appreciated!

      -luke-



        • 1. Re: Synchronizing MessageDrivenContext
          amadeuz

          Sorry forgot to mention that I'm using:

          - JBoss 3.2.8SP1
          - Hibernate 3.0
          - JBossMQ Queue, async processing with MDB (onMessage())

          Thanks!

          • 2. Re: Synchronizing MessageDrivenContext
            genman


            Not sure why you'd have to synchronize on "context". Is "context" a static variable? Each thread should have its own MDB instance.

            • 3. Re: Synchronizing MessageDrivenContext
              amadeuz

              Yes you are right that each thread has its own MDB instance and each of them has their own context, but because the container have the access to the context too, and roll it back in certain cases , that makes it hard to control it unless I synchronize it.

              For example, the following happened chronologically:

              1. onMessage() was invoked
              2. Connection# 1 was obtained to make query as part of the message processing
              3. Query is made and returned
              4. Container roll back context
              5. Connection# 2 was 'attempted' to be obtained to make an update
              6. Because context has been rolled back, exception thrown because No. 5 is not aware of the context roll back (please let me know if there's a way for Hibernate to be aware of it elegantly)

              • 4. Re: Synchronizing MessageDrivenContext
                genman

                I'm not following your synchronization issue. How is context visible to multiple threads?

                You can test before step 5 using a context.getRollbackOnly(), or I would probably just swallow the exception.

                • 5. Re: Synchronizing MessageDrivenContext
                  amadeuz

                  genman,

                  to answer your question, context is visible to the container, otherwise it won't be able to roll it back if needed to. no? the 'multiple threads' are container and the mdb thread itself so there are 2 threads.