skip to content

What does JobOperator.startNextInstance do, and what must the Job provide for it to work?

level: middleimportance: should knowfreq 45%

answer

  1. Instance identity = name + identifying params
  2. Incrementer.getNext computes next params
  3. RunIdIncrementer bumps run.id
  4. No incrementer → startNextInstance fails
  5. start = you supply params; startNextInstance = derived

basics

~20 s

startNextInstance runs a new instance of a job automatically. It uses the job's JobParametersIncrementer to derive the next parameters from the previous run — for example bumping a run.id counter — so each call is a distinct JobInstance.

solid answer

~40 s

A JobInstance in Spring Batch is uniquely keyed by the job name plus its *identifying* JobParameters. To run 'the same' job again — a nightly load, say — you need different identifying parameters each time, or you'd hit JobInstanceAlreadyCompleteException. startNextInstance(jobName) automates that: it finds the last JobInstance, asks the Job's JobParametersIncrementer to compute the next parameters from the previous ones, and starts a fresh instance with them. The classic incrementer is RunIdIncrementer, which adds/increments a run.id long parameter. You register it with JobBuilder.incrementer(...). If the job has no incrementer, startNextInstance fails. This is ideal for scheduled/repeating jobs where the business parameters are otherwise identical; you don't want to hand-craft a unique parameter on every trigger. It's distinct from start(jobName, props), where you supply the parameters yourself.

code

java · 10 lines
java
@Bean
public Job dailyJob(JobRepository jobRepository, Step step) {
    return new JobBuilder("dailyJob", jobRepository)
            .incrementer(new RunIdIncrementer()) // enables startNextInstance
            .start(step)
            .build();
}

// Each call makes a NEW JobInstance via run.id increment:
Long executionId = jobOperator.startNextInstance("dailyJob");

go deeper

for a junior

Knows it starts a fresh run and RunIdIncrementer bumps a counter.

for a middle

Explains instance identity, the incrementer's getNext, and why it's needed for repeated jobs.

for a senior

Contrasts start vs startNextInstance and warns against timestamp-as-parameter hacks.

for a principal

Discusses custom incrementers and metadata/restart implications of parameter identity choices.

**The identity problem.** Spring Batch identifies a `JobInstance` by `{jobName + identifying JobParameters}`. Once an instance completes successfully, it cannot be run again — attempting it throws `JobInstanceAlreadyCompleteException`. So a job you want to run repeatedly (nightly ETL, hourly report) needs *some* identifying parameter that changes each run. **What startNextInstance does.** `Long startNextInstance(String jobName)`: 1. Locates the most recent `JobInstance` for that job name (via `JobExplorer`/`JobRepository`). 2. Retrieves that instance's `JobParameters`. 3. Passes them to the `Job`'s configured `JobParametersIncrementer.getNext(JobParameters)` to compute the *next* parameter set. 4. Starts a new instance with those parameters and returns the new execution id. If there is no prior instance, it starts the first one (the incrementer is called with empty parameters). **JobParametersIncrementer.** This is a one-method interface: `JobParameters getNext(JobParameters parameters)`. The built-in `RunIdIncrementer` reads a long parameter named `run.id` (default 0), increments it, and returns parameters carrying the new value. Because `run.id` is an *identifying* parameter, each incremented value yields a new `JobInstance`. You can write custom incrementers — e.g. rolling a date parameter forward by one day. **Wiring.** Attach the incrementer when building the Job: ```java new JobBuilder("dailyJob", jobRepository) .incrementer(new RunIdIncrementer()) .start(step) .build(); ``` Without it, `startNextInstance` has nothing to compute the next parameters from and fails. **start vs startNextInstance.** - `start(jobName, Properties)` — *you* provide the parameters; used when each run genuinely differs (different input file, different date you pass in). - `startNextInstance(jobName)` — Spring *derives* the parameters via the incrementer; used when successive runs are otherwise identical and just need a fresh identity. **Gotchas.** - The incrementer only changes what *it* changes. If you also add a date/timestamp identifying parameter elsewhere, instance identity depends on that too. - `run.id` is meaningless business-wise; don't rely on it as a domain key — it exists purely to distinguish instances. - startNextInstance is about *new* instances, not resuming a failed one — that's `restart`. - Using `System.currentTimeMillis()` as an ad-hoc unique parameter is a common alternative to an incrementer, but it defeats the ability to restart a specific failed instance cleanly and pollutes metadata; a proper incrementer is preferred.

  • What happens if you call startNextInstance on a job with no incrementer?
    It fails — there is no strategy to derive the next parameters, so Spring cannot create a distinct next instance.
  • Why can't you just call start with the same parameters every night?
    Once an instance with those identifying parameters completes, re-running throws JobInstanceAlreadyCompleteException; identity must change, which the incrementer provides.

saying these in an interview costs you the question

  • Thinking startNextInstance restarts a failed run (that's restart)
  • Believing run.id has business meaning
  • Assuming startNextInstance works without an incrementer configured

context