Spring Batch
scheduled jobs
Java
task scheduling
batch processing

How to trigger a scheduled Spring Batch Job?

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

A scheduled Spring Batch job is usually triggered by combining Spring scheduling with a JobLauncher. The important detail is not just starting the job on a timer, but giving each execution unique JobParameters so Spring Batch treats each run as a new job instance.

The Basic Scheduling Pattern

Spring Batch does not schedule jobs by itself. It provides the batch model, while Spring's scheduling support provides the clock.

The usual setup is:

  • define a Job
  • inject a JobLauncher
  • create a method annotated with @Scheduled
  • call jobLauncher.run(job, params) from that method

First enable scheduling:

java
1import org.springframework.boot.SpringApplication;
2import org.springframework.boot.autoconfigure.SpringBootApplication;
3import org.springframework.scheduling.annotation.EnableScheduling;
4
5@SpringBootApplication
6@EnableScheduling
7public class BatchApplication {
8    public static void main(String[] args) {
9        SpringApplication.run(BatchApplication.class, args);
10    }
11}

Then create the scheduler component:

java
1import org.springframework.batch.core.Job;
2import org.springframework.batch.core.JobParameters;
3import org.springframework.batch.core.JobParametersBuilder;
4import org.springframework.batch.core.launch.JobLauncher;
5import org.springframework.scheduling.annotation.Scheduled;
6import org.springframework.stereotype.Component;
7
8@Component
9public class JobScheduler {
10    private final JobLauncher jobLauncher;
11    private final Job importUsersJob;
12
13    public JobScheduler(JobLauncher jobLauncher, Job importUsersJob) {
14        this.jobLauncher = jobLauncher;
15        this.importUsersJob = importUsersJob;
16    }
17
18    @Scheduled(cron = "0 0 * * * *")
19    public void runJob() throws Exception {
20        JobParameters params = new JobParametersBuilder()
21                .addLong("scheduledAt", System.currentTimeMillis())
22                .toJobParameters();
23
24        jobLauncher.run(importUsersJob, params);
25    }
26}

This example runs at the top of every hour.

Why Unique Parameters Matter

Spring Batch identifies a job instance by its job name plus identifying parameters. If you run the same job again with the same identifying parameters and the previous instance completed successfully, Spring Batch throws JobInstanceAlreadyCompleteException.

That is why a timestamp, run id, or business date is usually added.

For example, this is risky for recurring scheduling:

java
JobParameters params = new JobParametersBuilder()
        .addString("type", "hourly-import")
        .toJobParameters();

Those parameters never change, so after the first successful execution, later scheduled runs are duplicates from Spring Batch's perspective.

A timestamp solves that for generic periodic jobs. A business date is often better when reruns need to target a specific input window explicitly.

A Minimal Job Configuration

Here is a simple job with one tasklet step:

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    @Bean
15    public Step sampleStep(JobRepository jobRepository,
16                           PlatformTransactionManager transactionManager) {
17        return new StepBuilder("sampleStep", jobRepository)
18                .tasklet((contribution, chunkContext) -> {
19                    System.out.println("Batch job ran");
20                    return org.springframework.batch.repeat.RepeatStatus.FINISHED;
21                }, transactionManager)
22                .build();
23    }
24
25    @Bean
26    public Job importUsersJob(JobRepository jobRepository, Step sampleStep) {
27        return new JobBuilder("importUsersJob", jobRepository)
28                .start(sampleStep)
29                .build();
30    }
31}

With this in place, the scheduler can launch the job repeatedly.

Cron Versus Fixed Delay

Use cron when the job must align with wall-clock time, such as every day at 02:00. Use fixedDelay or fixedRate when you care about elapsed intervals.

Examples:

java
@Scheduled(cron = "0 0 2 * * *")
java
@Scheduled(fixedDelay = 300000)

For business batch jobs, cron is more common because the schedule is usually tied to reporting windows or data arrival times.

Prevent Overlapping Runs

A scheduled job can start while the previous run is still executing. That may be acceptable, or it may corrupt processing semantics.

Common ways to avoid overlap are:

  • check the JobExplorer for running executions before launching
  • use a distributed lock if multiple application instances can schedule the same job
  • offload scheduling to Quartz or an external orchestrator for clustered deployments

A simple in-process scheduler is fine for one application instance. For multiple nodes, you need coordination.

When Quartz Or An External Scheduler Is Better

@Scheduled is lightweight and usually enough for one service instance. If you need persistence, clustering, missed-trigger recovery, or calendar-style scheduling rules, Quartz is a stronger choice.

In some systems, the cleanest design is to let an external scheduler such as Kubernetes CronJob, Airflow, or a platform scheduler call an endpoint or launch the application at the right time. That keeps scheduling concerns outside the batch service.

Common Pitfalls

  • Reusing the same JobParameters for every scheduled run.
  • Forgetting that @Scheduled runs in every application instance unless you add coordination.
  • Allowing a new run to start before the previous run finishes.
  • Treating Spring Batch as if it included scheduling automatically.
  • Using fixed-rate scheduling when the real requirement is a wall-clock cron schedule.

Summary

  • Schedule a Spring Batch job by combining @Scheduled with JobLauncher.
  • Always pass unique identifying parameters for recurring executions.
  • Use cron for calendar-based schedules and fixed delay for interval-based schedules.
  • Prevent overlapping runs when job duration can exceed the schedule interval.
  • For clustered or highly managed scheduling, consider Quartz or an external scheduler.

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.