spring-batch: Unable to use Job Scope beans in a multi-threaded or partitioned step [BATCH-2269]

David Geary opened BATCH-2269 and commented

Attempting to access a JobScope bean from a worker thread in a thread pool as part of a multi-threaded or partitioned step gives the following exception

Caused by: java.lang.IllegalStateException: No context holder available for job scope
        at org.springframework.batch.core.scope.JobScope.getContext(JobScope.java:153)
        at org.springframework.batch.core.scope.JobScope.get(JobScope.java:92)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:338)

This is due to the fact the JobExecution is stored in a ThreadLocal and it isn’t set up on the worker threads.


Affects: 3.0.1

Reference URL: http://stackoverflow.com/questions/24558703/multi-threaded-acces-to-job-scope-beans-in-spring-batch-3-0

18 votes, 21 watchers

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 16 (2 by maintainers)

Most upvoted comments

Carlos Silva commented

We also had this problem, so we define a tweaked TaskExecutor that registers each thread in the JobSynchronizationManager, and in finally it releases it:

    TaskExecutor taskExecutor() {
        return new SimpleAsyncTaskExecutor() {
            @Override
            protected void doExecute(Runnable task) {
                //gets the jobExecution of the configuration thread
                def jobExecution = JobSynchronizationManager.context.jobExecution
                super.doExecute(new Runnable() {
                    @Override
                    void run() {
                        JobSynchronizationManager.register(jobExecution)

                        try {
                            task.run()
                        } finally {
                            JobSynchronizationManager.release()
                        }
                    }
                })
            }
        }
    }

Then we use that executor:

new FlowBuilder<SimpleFlow>('readControlFilesFlow')
               .start(firstStep)
               .split(taskExecutor())
               .add(anotherStep)
               .end()