Announcement Announcement Module
Collapse
No announcement yet.
WAS 5.1 Transaction timeout silently rolls back TX. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • WAS 5.1 Transaction timeout silently rolls back TX.

    First, I would like to say Spring is an excellent product, and I'm always impressed with how naturally it seem to integrate into our existing applications.

    I'm experiencing what I would consider to be an issue. We're running WAS 5.1 servers and seeing troublesome behavior from the JtaTransactionManager. The issue occurs when a TX times out. It appears the WAS is just setting the UserTransaction status to Status.STATUS_MARKED_ROLLBACK. This issue is that the JtaTransactionManager via DefaultTransactionStatus and JtaTransactionObject is seeing this TX as isRollbackOnly before it attempts to commit, and instead rolls the TX back and returns normally.
    The combination of how WAS has chosen to handle TX timeouts, and the way Spring has implemented JtaTransactionManager results in TX's rolling back silently and application code proceeding unaware.

    I'm not sure if there is something I'm overlooking on the Spring or WAS side that would cause an exception to be raised in the timeout situations. It may also be possible that this is exactly how things are intended to work. I just wanted to raise the issue, and see what kind of feedback I would get.

    Thanks,
    Matt

  • #2
    Hi Matt,

    I've just encountered the same issue with Weblogic 6.1 with both Spring 1.1.5 and 1.2. I personally think this is a Spring issue, simply because when the same thing happens with EJB CMT, an exception is always thrown. Also, it is a race condition in my situation. Sometimes I get an exception, sometimes I don't. I posted to spring-developer with this issue.

    Regards,
    Dave

    Comment


    • #3
      Have you tried using WebSphereTransactionManagerFactoryBean? Quote from the javadocs:

      FactoryBean that retrieves the JTA TransactionManager for IBM's WebSphere application servers (versions 5.1, 5.0 and 4).

      Uses WebSphere's static access methods to obtain the JTA TransactionManager, which is different for WebSphere 5.1, 5.0 and 4. (Please, dear WebSphere team, stop changing your TransactionManager access methods from version to version!)

      Comment


      • #4
        Thanks for reporting this! JTA implementations seem to mark transaction as rollback-only when they have timed out, without further indication. So unless you attempt an actual resource operation after the timeout, there is no guarantee than an exception gets thrown before commit.

        If Spring discovers a rollback-only status, it assumes that the application has set the transaction to rollback-only and triggers a silent rollback. This will usually happen when TransactionStatus.setRollbackOnly() has been called, instead of configuring a rollback rule, with an application-level exception getting thrown.

        In the case of a JTA timeout, the rollback-only marker comes from the JTA subsystem, though. Spring effectively misinterprets that marker as driven by the application, which leads to an inappropriate silent reaction. I'll fix that for Spring 1.2.1, although it's unfortunately not that trivial for the general case.

        Juergen

        Comment


        • #5
          FYI, this has been fixed in CVS, and should already be available in the latest nightly snapshots. Feel free to give the latter a try!

          This fix will be part of Spring 1.2.1 (scheduled for this Friday).

          Juergen

          Comment


          • #6
            Hello everybody.

            JtaTransactionManager.shouldCommitOnGlobalRollback Only() always returns true, so Spring calls commit if the container marks the transaction to be rolled back.

            Under JBoss, calling commit() in that situation causes the container's transaction manager to silently discard the call and finally calling rollback(), so the application is not notified about the final rollback.

            The workaround is to extend JtaTransactionManager with a custom implementation which overrides the shouldCommitOnGlobalRollbackOnly() method, just to return false. In this case we receive a UnexpectedRollbackException.

            Wouldn't be easier to allow configuring the behaviour of this call by means of the appropiate setter method?

            Something like void setShouldCommitOnGlobalRollbackOnly(boolean) could be very useful to configure the desired behaviour without extending the code.

            Thank you very much.

            JP

            Comment


            • #7
              Wow, thanks for the fast response. I haven't had a chance to test 1.2.1 out yet but it sounds like it fits the bill. I'm glad I could find the issue. I had assumed that it was specifically due to WAS5.1's JTA impl but looks like I wasn't then only one.

              Matt,

              Comment


              • #8
                Originally posted by jplsaez
                JtaTransactionManager.shouldCommitOnGlobalRollback Only() always returns true, so Spring calls commit if the container marks the transaction to be rolled back.

                Under JBoss, calling commit() in that situation causes the container's transaction manager to silently discard the call and finally calling rollback(), so the application is not notified about the final rollback.

                The workaround is to extend JtaTransactionManager with a custom implementation which overrides the shouldCommitOnGlobalRollbackOnly() method, just to return false. In this case we receive a UnexpectedRollbackException.

                Wouldn't be easier to allow configuring the behaviour of this call by means of the appropiate setter method?
                Thanks for reporting this. I would have expected every JTA implementation's commit to throw a RollbackException if the global transaction has been marked rollback-only, but obviously JBoss doesn't follow this rule...

                Instead of introducing configurable behavior in Spring's AbstractPlatformTransactionManager (which would require the user to be aware of the specific JTA behavior), I've added a check to the existing implementation:

                If we detect a global rollback-only marker and are told to attempt a commit in this case (which JtaTransactionManager does), we'll check whether the doCommit call throws an exception. If it doesn't, we'll throw an UnexpectedRollbackException ourselves.

                That should cover all cases, as far as I can see: If JTA commit didn't throw an exception itself in case of a global rollback-only, we'll react with a proper exception in Spring. But if JTA commit does throw an exception itself, we'll keep it and its specific error message.

                This will be available in the next nightly snapshot and in the upcoming release 1.2.2. Feel free to give it an early try on JBoss!

                Juergen

                Comment


                • #9
                  Hi,

                  I've just met with this UnexpectedException in an other scenario; where I was doing programmative rollback in my code, but wanted to return a value from the TransactionCallback.
                  While earlier it worked, this is not possible now, since the code throws an exception which swallows the return value.
                  For example I've had:

                  Code:
                  Integer id = transtemplate.execute(new TransactionCallback() {
                  
                  			public Object doInTransaction(TransactionStatus status) {
                  				// will be rolled back
                  				status.setRollbackOnly();
                                                  // do some speculative calculation in db that's going to be rolled back 
                  				
                  				return result;
                  			}
                  		});
                  As a workaround I throw now a special exception which contains the result value, but I feel this is not very nice as is. Is there any other way doing it?

                  Regards,
                  Zoltan
                  [/code]

                  Comment

                  Working...
                  X