Understanding Spring Batch Job and Step Management
Spring Batch provides a robust framework for managing jobs, handling their state, and enabling restartability. This tutorial will explain key concepts like JobInstance
, JobExecution
, StepExecution
, and ExecutionContext
, and how they are used to control a job's lifecycle.
JobInstance
A JobInstance
is a logical representation of a batch job. It's uniquely identified by the combination of a Job name and the Job Parameters used when it was launched. For example, a "DailyReport" job with a parameter for "reportDate=2025-09-16" will always correspond to the same JobInstance
. When you run a job with the same parameters, Spring Batch recognizes that it's the same logical job and reuses the existing JobInstance
.
By default, Spring Batch will not re-execute any Step
that has already completed successfully within a given JobInstance
.
JobExecution
and StepExecution
While a JobInstance
represents the logical job, a JobExecution
represents a single attempt to run that job. Every time you launch a job, a new JobExecution
is created. Similarly, a StepExecution
represents a single attempt to run a step. JobExecution
and StepExecution
are never reused. They track the start time, end time, status, and other runtime details of a specific execution attempt.
ExecutionContext
An ExecutionContext
is a collection of key-value pairs that are persisted between job runs and executions. It acts as a storage space for data you want to preserve for a future restart.
-
Job-scoped
ExecutionContext
: Data is persisted to the database after each step completes. -
Step-scoped
ExecutionContext
: Data is persisted after each chunk is committed.
ExecutionContext
is a powerful tool for maintaining state. For example, you can store a file name, a counter, or a database cursor position in the ExecutionContext
so that when a job is restarted, it can resume from where it left off.
Restarting a Job
Restartability is a core feature of Spring Batch. However, there are some rules:
-
Successful Jobs Are Not Restartable: By default, if a
JobInstance
(identified by its parameters) has a finalExitStatus
ofCOMPLETED
, Spring Batch will throw aJobExecutionException
if you try to run it again. This prevents re-processing data that has already been successfully handled. -
Empty Parameters: A job launched without any parameters is considered a new
JobInstance
each time, so it can be re-run even if the previous run was successful. -
Preventing Restart: You can use
.preventRestart()
on theJobBuilder
to explicitly disallow a job from being restarted.
When a job is restarted after a failure, Spring Batch automatically skips any steps that completed successfully in the previous attempt and only re-executes the step where the failure occurred.
Restarting a Step
By default, when a job restarts, any previously successful steps are skipped. They do not throw an exception, they simply don't run. This behavior can be changed using .allowStartIfComplete(true)
on the StepBuilder
, which will force a step to be re-executed even if it completed successfully in a previous run.
-
Execution Limit: To prevent infinite loops or excessive retries, you can set a restart limit for a step using
.startLimit(int)
. If the number of attempts exceeds this limit, aJobExecutionException
is thrown. -
Resuming from Failure: When a step fails, it automatically starts from the exact point of failure on restart. For example, if an
ItemReader
fails on the 100th line, it will resume reading from the 100th line on the next run. You can override this behavior and force the step to restart from the beginning by calling.saveState(false)
on theItemReader
.
Lifecycle Listeners
Spring Batch provides a way to execute custom logic at key points in a job's lifecycle using listeners.
-
JobExecutionListener
: Use this to execute code before (@BeforeJob
) and after (@AfterJob
) a job starts and ends. -
StepExecutionListener
: Use this to execute code before (@BeforeStep
) and after (@AfterStep
) a step starts and ends.
You can implement these interfaces or use the corresponding annotations (@BeforeJob
, @AfterJob
, @BeforeStep
, @AfterStep
) to attach custom logic to your jobs and steps. You then register these listeners using the .listener()
method on the JobBuilder
or StepBuilder
.
Top comments (0)