Announcement Announcement Module
No announcement yet.
Required transaction isolation for SimpleAsyncTaskExecutor - race condition? Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Required transaction isolation for SimpleAsyncTaskExecutor - race condition?

    I have an issue when executing a new job asynchronously, through a web request. My web controller is wrapped by a TransactionInterceptor, and calls a SimpleJobLauncher configured with a SimpleAsyncTaskExecutor. The Launcher calls jobRepository.createJobExecution(), then the Job is executed in a new thread, and therefore outside my transaction. The transaction in which the jobExecution is created has not committed until the web controller completes.

    Because the job execution begins before the transaction on the web request thread has committed, the job's thread does not see the newly created job and throws
    org.springframework.batch.core.repository.dao.NoSuchObjectException: Invalid JobExecution, ID 8 not found.
    	at org.springframework.batch.core.repository.dao.JdbcJobExecutionDao.updateJobExecution(
    	at org.springframework.batch.core.job.SimpleJob.execute(
    With a breakpoint on the Job's execute() method, the problem can be avoided by giving the web request time to return.

    It seems that the transaction isolation on the thread calling the Executor must be ISOLATION_READ_UNCOMMITTED for this use case to work. Does that seem true? It feels dirty. (haha "dirty read" pun)


  • #2
    Originally posted by jakeherringbone View Post
    The transaction in which the jobExecution is created has not committed until the web controller completes.
    Why is that? It could definitely be a problem. The create* method in JobRepository definitely needs special treatment (as per reference guide), because if it is atomic then it prevents concurrent execution of the same job. For this reason it needs to execute as fast as possible, but as isolated as possible (the Javadocs recommend at least READ_COMMITTED). The samples use propagation=REQUIRES_NEW, so it executes and commits immediately, and the reference guide strongly recommends this setting also.


    • #3
      I'm confused as to what's going on here. Why would you want to allow an outside transaction to contain your entire batch job? Aside from screwing up your metadata by causing dirty read conditions (as you encountered) and potentially preventing nested transactions from working, it just smells funky to me.

      Is there a reason you're not using the recommended AOP transaction advice on the org.springframework.batch.core.repository pointcut? (I forget the exact pointcut, but I'm sure you get my drift.) Or is it just not working for some reason?

      Seems to me the advice would take care of this if properly configured. When set up as Dave suggests with the REQUIRES_NEW rule, it would create a transaction completely independent of your web controller's transaction.
      Last edited by dkaminsky; Mar 30th, 2008, 05:13 AM.


      • #4
        Yes, thank you both, I had not set up the transaction around the *Create* methods as the documentation instructs. My project didn't even depend on AOP before - I guess there is no way around it here, as the transaction must be demarcated in the client configuration.