Spring Batch
Controller
Java
Spring Framework
Batch Processing

run spring batch job from the controller

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

You can start a Spring Batch job from a web controller, but you should do it in a controlled way. The controller should trigger the job and return a clear execution result, not contain the batch logic itself.

How Spring Batch Launching Works

Spring Batch separates job definition from job execution. A Job describes the steps, and a JobLauncher starts it with a set of JobParameters. Those parameters matter because Spring Batch uses them to identify job instances.

A minimal controller-based launch flow looks like this:

  1. inject JobLauncher
  2. inject the Job you want to run
  3. build unique parameters
  4. call jobLauncher.run(job, params)
  5. return the execution id or status

Example Configuration

This example defines a small job that logs a message. In a real application, the step would read, process, and write records.

java
1import org.springframework.batch.core.Job;
2import org.springframework.batch.core.Step;
3import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
4import org.springframework.batch.core.job.builder.JobBuilder;
5import org.springframework.batch.core.repository.JobRepository;
6import org.springframework.batch.core.step.builder.StepBuilder;
7import org.springframework.context.annotation.Bean;
8import org.springframework.context.annotation.Configuration;
9import org.springframework.transaction.PlatformTransactionManager;
10
11@Configuration
12@EnableBatchProcessing
13public class BatchConfig {
14
15    @Bean
16    public Step demoStep(JobRepository jobRepository,
17                         PlatformTransactionManager transactionManager) {
18        return new StepBuilder("demoStep", jobRepository)
19                .tasklet((contribution, chunkContext) -> {
20                    System.out.println("Running batch step");
21                    return org.springframework.batch.repeat.RepeatStatus.FINISHED;
22                }, transactionManager)
23                .build();
24    }
25
26    @Bean
27    public Job demoJob(JobRepository jobRepository, Step demoStep) {
28        return new JobBuilder("demoJob", jobRepository)
29                .start(demoStep)
30                .build();
31    }
32}

Launching From A REST Controller

The controller should create unique parameters so repeated requests do not collide with an already completed job instance.

java
1import org.springframework.batch.core.Job;
2import org.springframework.batch.core.JobExecution;
3import org.springframework.batch.core.JobParameters;
4import org.springframework.batch.core.JobParametersBuilder;
5import org.springframework.batch.core.launch.JobLauncher;
6import org.springframework.http.ResponseEntity;
7import org.springframework.web.bind.annotation.PostMapping;
8import org.springframework.web.bind.annotation.RequestMapping;
9import org.springframework.web.bind.annotation.RestController;
10
11@RestController
12@RequestMapping("/jobs")
13public class JobController {
14
15    private final JobLauncher jobLauncher;
16    private final Job demoJob;
17
18    public JobController(JobLauncher jobLauncher, Job demoJob) {
19        this.jobLauncher = jobLauncher;
20        this.demoJob = demoJob;
21    }
22
23    @PostMapping("/demo")
24    public ResponseEntity<String> runDemoJob() throws Exception {
25        JobParameters params = new JobParametersBuilder()
26                .addLong("startedAt", System.currentTimeMillis())
27                .toJobParameters();
28
29        JobExecution execution = jobLauncher.run(demoJob, params);
30        return ResponseEntity.accepted()
31                .body("Job started with execution id: " + execution.getId());
32    }
33}

Using System.currentTimeMillis() makes each request produce a new job instance. If you need idempotent behavior, use business keys instead and decide how reruns should work.

Synchronous Versus Asynchronous Launching

By default, the launcher may execute the job on the request thread, depending on configuration. That is acceptable for very small jobs, but long-running jobs should usually run asynchronously. Otherwise the HTTP request may time out while the batch is still working.

A common production pattern is:

  • controller starts the job
  • controller returns 202 Accepted
  • client polls a status endpoint
  • job execution details come from JobExplorer or the metadata tables

This keeps the web layer responsive and avoids tying batch duration to request timeouts.

Tracking Status

If you want to expose execution status, query the job repository rather than storing ad hoc flags.

java
1import org.springframework.batch.core.explore.JobExplorer;
2import org.springframework.web.bind.annotation.GetMapping;
3import org.springframework.web.bind.annotation.PathVariable;
4
5@GetMapping("/executions/{id}")
6public ResponseEntity<String> getStatus(@PathVariable Long id) {
7    var execution = jobExplorer.getJobExecution(id);
8    if (execution == null) {
9        return ResponseEntity.notFound().build();
10    }
11    return ResponseEntity.ok(execution.getStatus().toString());
12}

That approach stays aligned with how Spring Batch already models executions and restarts.

Common Pitfalls

The main mistake is launching the same job with the same parameters and expecting it to run again. Spring Batch treats that as the same job instance and may reject it once completed. Add a unique parameter when the goal is a fresh execution.

Another issue is putting heavy batch logic directly in the controller. The controller should only trigger work. Business logic belongs in the job, step, reader, processor, and writer components.

Be careful with long-running synchronous requests. If the job takes minutes, the browser or reverse proxy may give up before the batch ends. Prefer asynchronous execution and status tracking.

Finally, secure the endpoint. A batch trigger is an operational action, not a public API. Limit who can start jobs and consider rate limits or audit logging.

Summary

  • Use a controller to trigger a Spring Batch Job, not to implement the batch logic itself.
  • Start jobs through JobLauncher and pass well-defined JobParameters.
  • Use unique parameters when each request should create a new job instance.
  • Prefer asynchronous execution for long-running jobs and return 202 Accepted.
  • Expose status from Spring Batch metadata instead of inventing a parallel tracking system.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.