Announcement Announcement Module
Collapse
No announcement yet.
Transaction setting for TaskletStep Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Transaction setting for TaskletStep

    Dear all,

    I have a tasklet that needs to do some DB updates.

    I have a brief scanning through TaskletStep, unlike ItemOrientedStep, it does not contains any self-controlled transaction. Therefore, I bet I should create transaction by AOP. I wonder where should I wrap the transaction? On the actual tasklet, or on the TaskletStep. It seems a bit confusing for me: In case of successful completion, step execution's update (in tasklet step) should perform in same txn as my business logic. However, in case my business logic got error, my txn should be rollbacked, but not the step execution one.

    What is the right way to configure for transaction for TaskletStep? Using NESTED propagation? I think simply wrapping tasklet with txn is not enough, as there are DB access in tasklet step, am I right?



    In fact I have tried both case, what is wierd is that I failed to open transaction around TaskletStep (Hibernate throws Session Is Closed exception, which happens mostly bcos of no active txn). If I put the pointcut around my own tasklet, it works well.

    My jobs are put under a child app context. Here are some key lines in the job's app context config:
    Code:
        <context:annotation-config/>
        <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
    
        <tx:advice id="batch.mystep.txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="execute" propagation="REQUIRES_NEW"
                    rollback-for="java.lang.Throwable" />
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
            <aop:advisor
                pointcut="execution(* org.springframework.batch.core.step.tasklet.TaskletStep.*(..))"
                advice-ref="batch.mystep.txAdvice" />
        </aop:config>
        <aop:config>
            <aop:advisor
                pointcut="execution(* com.taifook.mtss.mss.batch.job.FooTasklet.*(..))"
                advice-ref="batch.mystep.txAdvice" />
        </aop:config>
    
        <bean id="fooJob" parent="batch.simpleJob">
            <property name="steps">
                <bean id="step1" parent="batch.taskletStep">
                    <property name="tasklet">
                        <bean class="com.foo.FooTasklet"/>
                    </property>
                </bean>
            </property>
        </bean>
    batch.taskletStep, transactionManager, batch.simpleJob are things that defined parent app context. FooTasklet is using @Resource to inject my own service (which will do DB updates by Hibernate). Above setting will cause my service throwing Hibernate's Session Is Closed exception. If I change the pointcut to
    "execution(* com.foo.FooTasklet.*(..)"
    it works (but I am not sure if it is a correct setting). I just wonder why the txn is not working if I wrap it on TaskletStep. I have looked at the code and there seems no special things done on txn.

    Thanks a lot

    Adrian

  • #2
    You're correct, you should be wrapping the transaction around the Tasklet, and not the TaskletStep. The transaction advice around the repository ensures that other calls in the TaskletStep to the repository are wrapped in a transaction.

    Comment


    • #3
      Thx Lucas,

      I am facing one issue: There are some step listener that I need to do some DB updates.

      As I said in previous message, I failed to put a txn aspect around TaskletStep (but why does this happen?). I may want the action performed in listener be included in a txn (or even in the txn of tasklet, is it something normal?), I failed to do so...

      Is there any way to solve that?

      Thanks

      Comment


      • #4
        You can use an AOP interceptor on the Tasklet if you need do do something cross cutting and make sure it's in the same transaction. Most simple cases would be quite easily covered by simply including the code in the Tasklet implementation itself though. Or maybe using a composite Tasklet.

        Comment


        • #5
          Originally posted by Dave Syer View Post
          You can use an AOP interceptor on the Tasklet if you need do do something cross cutting and make sure it's in the same transaction. Most simple cases would be quite easily covered by simply including the code in the Tasklet implementation itself though. Or maybe using a composite Tasklet.
          Is it correct if I say the following statement?

          "If I need to do business-transaction-awared actions around tasklet, it is better to use AOP to have aspect around Tasklet's execute(). However, if it comes to ItemOritentedStep, I shall use ChunkListener instead."

          Comment


          • #6
            though a bit off-topic, may I know what magic happened in TaskletStep that seems cause txn propagation failed if I wrap txn advise around TaskletStep instead of Tasklet?

            Comment


            • #7
              Originally posted by adrianshum View Post
              Is it correct if I say the following statement?
              I think the literal answer to that question is a big "maybe". It is probably correct to say that AOP is tricky to use in the ItemOrientedStep case, and it is easy in the TaskletStep. But AOP is not necessarily *best* (your mileage may vary). And ChunkListener doesn't exist in the TaskletStep (no chunks), but it is great for executing stuff before and after every chunk in the ItemOrientedStep, but that isn't the only use case for a listener.

              Comment


              • #8
                Originally posted by adrianshum View Post
                though a bit off-topic, may I know what magic happened in TaskletStep that seems cause txn propagation failed if I wrap txn advise around TaskletStep instead of Tasklet?
                I have no idea. Maybe you could share a stack trace or something?

                Comment


                • #9
                  Originally posted by Dave Syer View Post
                  I have no idea. Maybe you could share a stack trace or something?
                  Sure
                  Code:
                  Exception in thread "SimpleAsyncTaskExecutor-1" org.hibernate.SessionException:Session is closed!
                          at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)
                          at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1621)
                          at 
                  .........
                          at com.taifook.mtss.mss.batch.job.FooTasklet.execute(FooTasklet.java:31)
                          at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:98)
                          at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:168)
                          at org.springframework.batch.core.job.SimpleJob.execute(SimpleJob.java:125)
                          at com.taifook.mtss.mss.batchsvr.core.MssContextClosingJob.execute(MssContextClosingJob.java:52)
                          at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:86)
                          at java.lang.Thread.run(Thread.java:595)
                  Here is the pointcut and txn settings I used:
                  Code:
                      <aop:config>
                          <!--aop:pointcut id="batch.taskletExecute" expression="execution(* org.springframework.batch.core.step.tasklet.Tasklet.execute(..))" / -->
                          <aop:pointcut id="batch.taskletExecute" expression="execution(* org.springframework.batch.core.step.tasklet.TaskletStep.execute(..))" />
                          <aop:advisor  pointcut-ref="batch.taskletExecute"  advice-ref="batch.tasklet.txAdvice"  order="10"/>
                      </aop:config>
                  
                      <tx:advice id="batch.tasklet.txAdvice" transaction-manager="transactionManager">
                          <tx:attributes>
                              <tx:method name="*" propagation="REQUIRES_NEW" rollback-for="java.lang.Throwable" />
                          </tx:attributes>
                      </tx:advice>
                  From the call stack, obviously no transaction related proxy appears before TaskletStep's execute.

                  However when I change to the remarked pointcut, it works.

                  Adrian

                  Comment


                  • #10
                    Originally posted by Dave Syer View Post
                    I think the literal answer to that question is a big "maybe". It is probably correct to say that AOP is tricky to use in the ItemOrientedStep case, and it is easy in the TaskletStep. But AOP is not necessarily *best* (your mileage may vary). And ChunkListener doesn't exist in the TaskletStep (no chunks), but it is great for executing stuff before and after every chunk in the ItemOrientedStep, but that isn't the only use case for a listener.
                    However, if I want the 'hooking' logic being transactional (included in my business txn), isn't that the only way?

                    Item Oriented Step controls txn itself, and I can only use Chunk Listener (I dunno where to put my aspect in such case) to put those txn awared hooking logic.

                    Tasklet use AOP for transactional control, which adding another aspect after the txn aspect seems to be the only way if I want the logic being transactional.

                    Comment


                    • #11
                      AOP is not the only way with TaskletStep. I gave three alternatives in my earlier post.

                      You are correct that ChunkListener is the framework listener with the largest scope to be included in the business transaction. However, if you want to do something at the beginning or end of a step it isn't the convenient. For the beginning of the step the most convenient way to ensure transactional consistency might be a special ItemReader or ItemWriter. For the end of the step the same would work, but it is quite OK to use a StepExecutionListener which is also an ItemStream, so that in the case of failure you get the same information back on restart. The same trick should work at the beginning for that matter.

                      Comment


                      • #12
                        I'd say the stack trace you posted shows that (as you already pointed out) the pointcut is not matching. No magic there. It would match if you used the interface (Step) instead of the implementation (TaskletStep) in the pointcut expression. This is academic anyway, as we have already determined that the step is the wrong place for a transaction.

                        Comment

                        Working...
                        X