Uploaded image for project: 'Spring Batch'
  1. Spring Batch
  2. BATCH-1767

OptimisticLockingFailureException updating step execution after commit failure

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 2.1.7
    • Fix Version/s: 4.0.0
    • Component/s: None
    • Labels:
      None
    • Environment:
      Spring 3.0.5
      Spring Batch 2.1.7
      Eclipselink 1.1.1

      Description

      It appears that if the commit fails, spring batch will get an OptimisticLockingFailureException when it tries to revert the changes to the step execution. In my particular case, I have a callback through EclipseLink to update history tables before a transaction is committed. If a failure occurs during this callback, the commit fails.

      From looking through the code and the attached log file, the step execution is updated and committed before the main transaction is committed. When the commit fails, the old values for the step execution (including version) are updated to the values before the chuck started. When control returns to AbstractStep.execute(), the OptimisticLockingFailureException is thrown when the step execution is updated with the failed status because the new version had already been committed to the database.

      2011-07-06 17:40:29,494 ERROR SimpleAsyncTaskExecutor-1 [org.springframework.batch.core.step.AbstractStep] Encountered an error saving batch meta data. This job is now in an unknown state and should not be restarted.
      org.springframework.dao.OptimisticLockingFailureException: Attempt to update step execution id=3225 with wrong version (35), where current version is 36
      at org.springframework.batch.core.repository.dao.JdbcStepExecutionDao.updateStepExecution(JdbcStepExecutionDao.java:185)
      at org.springframework.batch.core.repository.support.SimpleJobRepository.update(SimpleJobRepository.java:171)
      at sun.reflect.GeneratedMethodAccessor130.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
      at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
      at $Proxy77.update(Unknown Source)
      at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:244)
      at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
      at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
      at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
      at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
      at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
      at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:91)
      at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:89)
      at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
      at java.util.concurrent.FutureTask.run(FutureTask.java:138)
      at java.lang.Thread.run(Thread.java:662)

      1. BATCH-1767.log.gz
        17 kB
        Philippe Mouawad
      2. log-1.txt
        43 kB
        Quinton McCombs
      3. scenario.txt
        3 kB
        Kristof Buts

        Activity

        Hide
        membersound member sound added a comment -

        Any updates on this fix? I got the same problem...

        Show
        membersound member sound added a comment - Any updates on this fix? I got the same problem...
        Hide
        plastictoast James Home added a comment - - edited

        @Michael

        Regarding the comment: "With regards to why the copy method restores the version number...why wouldn't it? The intent is that there was a rollback so the state should match what was there before the rollback."

        The thing is, it's not actually a rollback in the database sense. You're really just resetting the counts the their previous values. It's a new update in a db sense, so surely it should use the appropriate version number. The policy of 'rolling back' the version number in a db update seems to be incompatible with the principle of version based optimistic locking that's being used by the dao.

        Show
        plastictoast James Home added a comment - - edited @Michael Regarding the comment: "With regards to why the copy method restores the version number...why wouldn't it? The intent is that there was a rollback so the state should match what was there before the rollback." The thing is, it's not actually a rollback in the database sense. You're really just resetting the counts the their previous values. It's a new update in a db sense, so surely it should use the appropriate version number. The policy of 'rolling back' the version number in a db update seems to be incompatible with the principle of version based optimistic locking that's being used by the dao.
        Hide
        zyro zyro added a comment -

        following the suggestion to flush the session in the writer, i think there is still a (slight..) chance for an exception being thrown (e.g. StaleObjectStateException) during the actual commit (which may flush again).
        when using a skip policy, shouldnt that exception result in a skip and not break the whole job execution leaving it in an UNKNOWN state?

        Show
        zyro zyro added a comment - following the suggestion to flush the session in the writer, i think there is still a (slight..) chance for an exception being thrown (e.g. StaleObjectStateException ) during the actual commit (which may flush again). when using a skip policy, shouldnt that exception result in a skip and not break the whole job execution leaving it in an UNKNOWN state?
        Hide
        xstian Christian Alfano added a comment -

        Are there news about this issue? Can we have a release date? or maybe a workaround in order to avoid the flush of the entity manager?

        Show
        xstian Christian Alfano added a comment - Are there news about this issue? Can we have a release date? or maybe a workaround in order to avoid the flush of the entity manager?
        Hide
        bukya1988 ravindar added a comment -

        Hi,

        Which version release fix the issue.Please response on this.

        Thanks,
        Ravindar.

        Show
        bukya1988 ravindar added a comment - Hi, Which version release fix the issue.Please response on this. Thanks, Ravindar.

          People

          • Assignee:
            mminella Michael Minella
            Reporter:
            quintonm Quinton McCombs
          • Votes:
            22 Vote for this issue
            Watchers:
            28 Start watching this issue

            Dates

            • Created:
              Updated: