What does the job-level restartable flag do, and what happens if you try to restart a non-restartable job?
answer
- default restartable = true
- preventRestart() → JobRestartException on relaunch
- one JobExecution per instance, ever
- job-level, not step startLimit/allowStartIfComplete
- use for non-idempotent one-shot jobs
basics
~10 sSetting a job's restartable property to false marks it as run-once-per-instance. If its execution fails and you relaunch with the same identifying parameters, Spring Batch refuses and throws JobRestartException instead of resuming.
solid answer
~40 sBy default a Job is restartable (`restartable = true`), so a FAILED/STOPPED JobInstance can be relaunched and resumed. Calling `preventRestart()` on the JobBuilder (setting the flag false) tells Spring Batch this JobInstance may only ever have ONE JobExecution. If that execution fails and you launch again with the same identifying parameters, the framework throws `JobRestartException` ("JobInstance already exists and is not restartable") rather than creating a second JobExecution. You'd use this for jobs where resuming is unsafe or meaningless — e.g. a non-idempotent one-shot operation where a partial rerun could corrupt data, and you'd rather force a fresh run with new parameters. Note this is distinct from the per-step `startLimit` / `allowStartIfComplete` controls, which tune behavior within a restartable job.
code
java · 13 lines@Bean
public Job oneShotJob(JobRepository jobRepository, Step migrateStep) {
return new JobBuilder("oneShotJob", jobRepository)
.preventRestart() // restartable = false
.start(migrateStep)
.build();
}
// First run FAILS. Relaunch with the SAME identifying parameters:
// jobLauncher.run(oneShotJob, sameParams)
// -> throws JobRestartException:
// "JobInstance already exists and is not restartable"
// To re-run you must use DIFFERENT identifying parameters (new JobInstance).go deeper
Know the flag exists and defaults to true; false means the instance can't be relaunched.
Name preventRestart(), the JobRestartException, and the one-execution-per-instance rule.
Contrast with COMPLETED (JobInstanceAlreadyCompleteException) and with step-level controls; justify when to use it.
Weigh restartable=false vs idempotent-resume designs for non-transactional side effects and operational rerun policy.
## The flag Every `Job` has a boolean **restartable** property, default **true**. In the builder API you set it false via `preventRestart()`: ```java new JobBuilder("oneShotJob", jobRepository) .preventRestart() // restartable = false .start(step) .build(); ``` ## What true (default) means A restartable job whose JobInstance last ended `FAILED` or `STOPPED` can be relaunched with the same identifying parameters; Spring Batch creates a new JobExecution and resumes from persisted state (skipping COMPLETED steps, resuming the failing step's last chunk). ## What false means The JobInstance is allowed **exactly one** JobExecution, ever. Consequences: - First launch runs normally. - If it fails and you launch again with the **same identifying parameters**, you get `JobRestartException` — message along the lines of *"JobInstance already exists and is not restartable."* No second JobExecution is created. - To run the work again you must supply **different identifying parameters**, which creates a brand-new JobInstance (a fresh run, not a resume). ## Why it exists / when to use Use `preventRestart()` when resuming a partially-completed instance would be **incorrect or dangerous**: - Non-idempotent side effects where re-running part of the job double-applies something and there's no safe checkpoint. - Jobs where the intended semantics are "this exact input runs once; if it fails, investigate and rerun as a new instance," so you never silently resume. ## Distinctions to keep straight - **restartable=false** is *job-level* and blocks the whole restart. It is NOT the same as: - **`startLimit(n)`** — a *step* property limiting how many times a step may be started across executions. - **`allowStartIfComplete(true)`** — a *step* property that forces a COMPLETED step to re-run on each restart. - restartable=false vs. a **COMPLETED** instance: a COMPLETED instance throws `JobInstanceAlreadyCompleteException`; a *non-restartable* instance that FAILED throws `JobRestartException`. Different exceptions, different causes. ## Gotcha People confuse "my job won't restart" caused by `preventRestart()` with the far more common cause: a **unique identifying parameter each run** creating a new JobInstance every time (which technically always "succeeds" but never resumes). Check both the flag and the parameter identity.
- What's the difference between the exception for a non-restartable failed job and a completed job?A non-restartable job that FAILED throws JobRestartException when you relaunch the same instance. A job that COMPLETED throws JobInstanceAlreadyCompleteException. The first is blocked by the restartable=false flag; the second because success is terminal.
- How do you re-run work for a non-restartable job after a failure?Launch with different identifying JobParameters so a new JobInstance is created — a fresh run from the start, not a resume. Combine with idempotent logic since the failed instance's partial effects may still be present.
saying these in an interview costs you the question
- Confusing job-level restartable=false with per-step startLimit or allowStartIfComplete
- Saying a non-restartable failed job throws JobInstanceAlreadyCompleteException (wrong exception)
- Thinking restartable=false makes the job re-run from scratch on relaunch (it blocks relaunch of that instance entirely)
- Assuming restartable defaults to false