Spring Batch: starting a job from within a Spring MVC contorller WITH A NEW THREAD

10,851

Solution 1

The official documentation describes your exact problem and a solution in 4.5.2. Running Jobs from within a Web Container:

[...] The controller launches a Job using a JobLauncher that has been configured to launch asynchronously, which immediately returns a JobExecution. The Job will likely still be running, however, this nonblocking behaviour allows the controller to return immediately, which is required when handling an HttpRequest.

Spring Batch http://static.springsource.org/spring-batch/reference/html-single/images/launch-from-request.png

So you were pretty close in trying to use TaskExecutor, however it needs to be passed to the JobLauncher instead:

<bean id="jobLauncher"
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
    <property name="taskExecutor" ref="taskExecutor"/>
</bean>

Disclaimer: I have never used Spring Batch...

Solution 2

The jobLauncher.run() method can be called in a new Thread like so:

@RequestMapping(value = "/upload")
public ModelAndView uploadInventory(UploadFile uploadFile, BindingResult bindingResult) {
  [...]

  final SomeObject jobLauncher = [...]
  Thread thread = new Thread(){
    @Override
    public void run(){
      jobLauncher.run([...]);
    }
  };
  thread.start();

  return mav;
}

The thread.start() line will spawn a new thread, and then continue to execute the code below it.

Note that, if jobLauncher is a local variable, it must be declared final in order for it to be used inside of the anonymous Thread class.

Solution 3

If you don't need to show the processing errors to your client, you can start the spring batch job in a seperate thread.

Share:
10,851
rapt
Author by

rapt

Updated on June 19, 2022

Comments

  • rapt
    rapt almost 2 years

    I have a Spring-Batch job that I launch from a Spring MVC controller. The controller gets an uploaded file from the user and the job is supposed to process the file:

    @RequestMapping(value = "/upload")
    public ModelAndView uploadInventory(UploadFile uploadFile, BindingResult bindingResult) {
    
        // code for saving the uploaded file to disk goes here...
    
        // now I want to launch the job of reading the file line by line and saving it to the database,
        // but I want to launch this job in a new thread, not in the HTTP request thread,
        // since I so not want the user to wait until the job ends.
        jobLauncher.run(
                        jobRegistry.getJob(JOB_NAME),
                        new JobParametersBuilder().addString("targetDirectory", folderPath).addString("targetFile", fileName).toJobParameters()
                        );
    
        return mav;
    }
    

    I've tried the following XML config:

    <job id="writeProductsJob" xmlns="http://www.springframework.org/schema/batch">
        <step id="readWrite">
            <tasklet task-executor="taskExecutor">
                <chunk reader="productItemReader" writer="productItemWriter" commit-interval="10" />
            </tasklet>
        </step>
    </job>
    
    <bean id="taskExecutor"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="5" />
        <property name="maxPoolSize" value="5" />
    </bean>
    

    ...but it seems like the multithreading happens only within the job boundaries itself. I.e., the controller thread waits until the job ends, and the job execution is handled by multiple threads (which is good but not the main thing I wanted). The main thing I wanted is that the job will be launched on a separate thread (or threads) while the controller thread will continue its execution without waiting for the job threads to end.

    Is there a way to achieve this with Spring-batch?

  • rapt
    rapt about 12 years
    I was thinking about it - but is there a setting for this in the spring-batch framework? E.g. suppose I want to have every Request start a new thread for its job, but only up to 10 such threads - if I have more than 10 files having to be processed at the moment than only ten will get their own new thread and the other files will be processed later, maybe by some global scheduler. Isn't it something that spring-batch developers already implemented (at least partially)?
  • rapt
    rapt about 12 years
    Thank you! exactly what I wanted! beginner's luck :)
  • Abhishek Nayak
    Abhishek Nayak over 9 years
    second link is 404, please update with the correct link.