skip to content

In Spring Batch, what is the difference between BatchStatus and ExitStatus?

level: juniorimportance: must knowfreq 55%

answer

  1. BatchStatus = enum, lifecycle, framework-owned
  2. ExitStatus = String code + description, extensible
  3. ExitStatus drives flow decisions
  4. ExitStatus derived from BatchStatus by default
  5. Both on JobExecution and StepExecution

basics

~20 s

BatchStatus is an enum (COMPLETED, FAILED, STARTED, STOPPED...) describing a job's or step's lifecycle state. ExitStatus is a string-code object (exitCode plus description) used mainly to decide flow between steps. Both live on every JobExecution and StepExecution.

solid answer

~40 s

BatchStatus is a fixed enum recording the technical lifecycle of a JobExecution or StepExecution: STARTING, STARTED, COMPLETED, STOPPING, STOPPED, FAILED, ABANDONED, UNKNOWN. The framework owns it and uses it internally (for example to decide whether a job can restart). ExitStatus is a value object holding a free-form String exitCode plus an exitDescription; its default codes mirror BatchStatus ('COMPLETED', 'FAILED'...) but you can set any custom code. The key practical difference: ExitStatus is what step-to-step flow transitions match against, so you customize ExitStatus to branch a job, while BatchStatus stays a canonical, non-extensible record of what actually happened. Every JobExecution and StepExecution carries both, and by default ExitStatus is derived from BatchStatus.

code

java · 12 lines
java
// Both statuses live on every execution
StepExecution stepExecution = ...;

BatchStatus status = stepExecution.getStatus();        // enum, e.g. BatchStatus.COMPLETED
ExitStatus exit = stepExecution.getExitStatus();       // value object

String code = exit.getExitCode();                      // "COMPLETED" (a String)
String desc = exit.getExitDescription();               // free text / stack trace

// Enum vs String — this is the essence of the difference:
boolean unsuccessful = status.isUnsuccessful();        // BatchStatus knows lifecycle severity
boolean matchesBranch = "COMPLETED".equals(code);      // ExitStatus matched as a String

go deeper

for a junior

Must know: BatchStatus = enum lifecycle, ExitStatus = String code, both present on executions.

for a middle

Should explain the default derivation and that ExitStatus is the branching key.

for a senior

Explains ownership (framework vs customizable), persistence columns, and independence of the two after customization.

for a principal

Frames the design rationale: closed canonical record vs open extensible outcome code.

## The two concepts Every `JobExecution` and every `StepExecution` in Spring Batch carries **two** status fields, and candidates constantly confuse them. ### BatchStatus `BatchStatus` is a Java **enum** in `org.springframework.batch.core`. Its values are: `COMPLETED`, `STARTING`, `STARTED`, `STOPPING`, `STOPPED`, `FAILED`, `ABANDONED`, `UNKNOWN`. Because it is an enum, it is a **closed, fixed set** — you cannot add your own value. It represents the **technical lifecycle state** of the execution and is owned and managed by the framework. It is what the `JobRepository` persists in the `BATCH_JOB_EXECUTION.STATUS` / `BATCH_STEP_EXECUTION.STATUS` columns, and it is what the framework consults to answer questions like *'is this execution still running?'* or *'may this job instance be restarted?'*. ### ExitStatus `ExitStatus` is **not an enum** — it is a plain **value object** (a class implementing `Comparable` and `Serializable`) with two important fields: - `exitCode` — a **String** (e.g. `"COMPLETED"`, `"FAILED"`, or anything you invent like `"COMPLETED_WITH_SKIPS"`) - `exitDescription` — a free-text String, typically a stack trace or human message. Spring ships constants for the common codes: `ExitStatus.COMPLETED`, `ExitStatus.FAILED`, `ExitStatus.STOPPED`, `ExitStatus.EXECUTING`, `ExitStatus.NOOP`, `ExitStatus.UNKNOWN`. Because the code is just a String, `ExitStatus` is **open/extensible** — that extensibility is the whole point. ## Why two? BatchStatus answers *'what technically happened to this execution?'* (a canonical record). ExitStatus answers *'what outcome code should influence what happens next?'* Flow decisions (which step runs next) are driven by the **ExitStatus string**, not by BatchStatus, precisely because you may want several distinct outcomes that all still map to `BatchStatus.COMPLETED` at the framework level. ## Default relationship At the end of a step or job, if you do not customize anything, the ExitStatus **is derived from** the BatchStatus: a step that ends `BatchStatus.COMPLETED` gets `ExitStatus.COMPLETED`, a `FAILED` BatchStatus yields `ExitStatus.FAILED`, and so on. So out of the box the two agree. ## Gotchas - ExitStatus is compared by `exitCode` String — case and exact spelling matter. - Customizing ExitStatus (e.g. in an `afterStep` listener) does **not** change the BatchStatus; the framework still records COMPLETED/FAILED independently. - ExitStatus has severity ordering via `and(...)`/`Comparable`; BatchStatus has its own severity via `max(...)`. They are separate mechanisms. ## When to use which - Read/inspect **BatchStatus** when you want the authoritative lifecycle outcome (monitoring, restart logic). - Set/customize **ExitStatus** when you want to influence branching or expose a finer-grained outcome code.

  • If you change a step's ExitStatus, does the BatchStatus change too?
    No. BatchStatus is recorded independently by the framework. Customizing ExitStatus (e.g. returning a new ExitStatus from afterStep) changes only the exit code used for branching/reporting; the persisted BatchStatus still reflects the technical outcome (COMPLETED/FAILED).
  • Which of the two would you match on to route a job down a different path?
    ExitStatus. Flow transitions compare the ExitStatus exitCode String, so custom codes let you branch. BatchStatus is a closed enum and is not meant for custom branching keys.

saying these in an interview costs you the question

  • Saying both are enums (ExitStatus is NOT an enum — it's a String-code value object).
  • Claiming ExitStatus and BatchStatus are always identical (they agree by default but ExitStatus can be customized).
  • Thinking BatchStatus can be extended with custom values.

context