13

I'm developing a Spring-Batch project using Spring-Boot and everything is going along nicely. I've done a few spring-batch examples (including some from spring.io), but I'm not sure what some of the stuff does, and "it just works" doesn't satiate me.

My spring boot main class implements CommandLineRunner and for this particular job the initial set up looked like

@Bean
public Job myJob(JobExecutionListenerSupport listener) {
    return myJobBuilderFactory.get(JOB)
            .listener(listener)
            .start(myStep())
            .build();
}

Which caused

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:790) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:777) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1191) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1180) [spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.bjc.providermodel.maintenance.MaintenanceApplication.main(MaintenanceApplication.java:20) [classes/:?]
Caused by: org.springframework.batch.core.repository.JobExecutionAlreadyRunningException: A job execution for this job is already running: JobInstance: id=99, version=0, Job=[myJob]

Why does changing the above bean to

@Bean
public Job myJob(JobExecutionListenerSupport listener) {
    return myJobBuilderFactory.get(JOB)
            .incrementer(new RunIdIncrementer())
            .listener(listener)
            .start(myStep())
            .build();
}

Make everything go smoothly? I attempted to read up on the doc for RunIdIncrementer and also read up a little here. From what I can tell it needs this incrementer to keep track of a particular set of jobs that are running to do "stuff", but not sure what stuff is exactly. The Spring-Boot abstraction is making it hard for me to know what's going on here

LumberSzquatch
  • 1,054
  • 3
  • 23
  • 46

1 Answers1

23

This isn't a "Boot thing" as much as it is a "Batch thing". Spring Batch has the rule that a JobInstance can only be run once to completion. This means that for each combination of identifying job parameters, you can only have one JobExecution that results in COMPLETE. A RunIdIncrementer will append an additional, unique parameter to the list of parameters so that the resulting combination would be unique...giving you a new JobInstance each time you ran the job with the same combination of identifying parameters.

The RunIdIncrementer is really just a special case of the JobParametersIncrementer which you can read more about in our documentation here.

Simeon Leyzerzon
  • 18,658
  • 9
  • 54
  • 82
Michael Minella
  • 20,843
  • 4
  • 55
  • 67
  • Given your explanation, should the sentence in the docs you referred to - `"Unlike JobLauncher (which requires a new JobParameters object that triggers a new JobInstance), if the parameters are different from any previous set of parameters, the startNextInstance method uses the JobParametersIncrementer tied to the Job to force the Job to a new instance:..."` read instead: "Unlike JobLauncher (which requires a new JobParameters object that triggers a new JobInstance), if the parameters are ***not*** different from any previous ..."? – Simeon Leyzerzon Aug 20 '23 at 12:34
  • Also, why, in this case, is the responsibility to add that extra `Job` attribute - incrementer - left to the framework's user, sounds like the framework should be able to decide to add it internally without any end user's involvement? Or am I not reading it right? – Simeon Leyzerzon Aug 20 '23 at 12:44