Skip unnecessary attempt at executing Job

...that was already executed as part of the "local" set.

Also added some howto docs on executing Batch jobs.

See gh-382
pull/365/head
Dave Syer 11 years ago
parent 3ad6c96ce5
commit 09f3ee14a4

@ -912,6 +912,19 @@ scripts can act as "poor man's migrations" - inserts that fail mean
that the data is already there, so there would be no need to prevent
the application from running, for instance.
### Spring Batch
If you are using Spring Batch then it comes pre-packaged with SQL
initialization scripts for most popular database platforms. Spring
Boot will detect your database type, and execute those scripts by
default, and in this case will switch the fail fast setting to false
(errors are logged but do not prevent the application from
starting). This is because the scripts are known to be reliable and
generally do not contain bugs, so errors are ignorable, and ignoring
them makes the scripts idempotent. You can switch off the
initialization explicitly using
`spring.batch.initializer.enabled=false`.
### Higher Level Migration Tools
Spring Boot works fine with higher level migration tools
@ -921,6 +934,31 @@ Flyway because it is easier on the eyes, and it isn't very common to
need platform independence: usually only one or at most couple of
platforms is needed.
## Execute Spring Batch Jobs on Startup
Spring Batch autoconfiguration is enabled by adding
`@EnableBatchProcessing` (from Spring Batch) somewhere in your
context.
By default it executes *all* `Jobs` in the application context on
startup (see
[JobLauncherCommandLineRunner](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherCommandLineRunner.java)
for details). You can narrow down to a specific job or jobs by
specifying `spring.batch.job.names` (comma separated job name
patterns).
If the application context includes a `JobRegistry` then
the jobs in `spring.batch.job.names` are looked up in the regsitry
instead of bein autowired from the context. This is a common pattern
with more complex systems where multiple jobs are defined in child
contexts and registered centrally.
See
[BatchAutoConfiguration](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java)
and
[@EnableBatchProcessing](https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java)
for more details.
<span id="discover.options"/>
## Discover Built-in Options for External Properties

@ -23,17 +23,20 @@ import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationEventPublisher;
@ -63,7 +66,7 @@ public class JobLauncherCommandLineRunner implements CommandLineRunner,
@Autowired(required = false)
private JobRegistry jobRegistry;
@Autowired
private JobRepository jobRepository;
@ -103,14 +106,12 @@ public class JobLauncherCommandLineRunner implements CommandLineRunner,
for (String jobName : jobsToRun) {
try {
Job job = this.jobRegistry.getJob(jobName);
JobExecution previousExecution = jobRepository.getLastJobExecution(jobName, jobParameters);
if (previousExecution == null || previousExecution.getStatus() != BatchStatus.COMPLETED) {
JobExecution execution = this.jobLauncher.run(job, jobParameters);
if (this.publisher != null) {
this.publisher.publishEvent(new JobExecutionEvent(execution));
}
if (this.jobs.contains(job)) {
continue;
}
} catch (NoSuchJobException nsje) {
execute(job, jobParameters);
}
catch (NoSuchJobException nsje) {
logger.debug("No job found in registry for job name: " + jobName);
continue;
}
@ -118,6 +119,20 @@ public class JobLauncherCommandLineRunner implements CommandLineRunner,
}
}
protected void execute(Job job, JobParameters jobParameters)
throws JobExecutionAlreadyRunningException, JobRestartException,
JobInstanceAlreadyCompleteException, JobParametersInvalidException {
String jobName = job.getName();
JobExecution previousExecution = this.jobRepository.getLastJobExecution(jobName,
jobParameters);
if (previousExecution == null || previousExecution.getStatus().isUnsuccessful()) {
JobExecution execution = this.jobLauncher.run(job, jobParameters);
if (this.publisher != null) {
this.publisher.publishEvent(new JobExecutionEvent(execution));
}
}
}
private void executeLocalJobs(JobParameters jobParameters)
throws JobExecutionException {
for (Job job : this.jobs) {
@ -128,10 +143,7 @@ public class JobLauncherCommandLineRunner implements CommandLineRunner,
continue;
}
}
JobExecution execution = this.jobLauncher.run(job, jobParameters);
if (this.publisher != null) {
this.publisher.publishEvent(new JobExecutionEvent(execution));
}
execute(job, jobParameters);
}
}

@ -114,29 +114,30 @@ public class BatchAutoConfigurationTests {
assertNotNull(this.context.getBean(JobRepository.class).getLastJobExecution(
"job", new JobParameters()));
}
@Test
public void testDefinesAndLaunchesNamedJob() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.batch.job.names:discreteRegisteredJob");
this.context.register(NamedJobConfigurationWithRegisteredJob.class, BatchAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class,
this.context.register(NamedJobConfigurationWithRegisteredJob.class,
BatchAutoConfiguration.class, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
JobRepository repository = this.context.getBean(JobRepository.class);
assertNotNull(this.context.getBean(JobLauncher.class));
this.context.getBean(JobLauncherCommandLineRunner.class).run();
assertNotNull(this.context.getBean(JobRepository.class).getLastJobExecution(
"discreteRegisteredJob", new JobParameters()));
assertNotNull(repository.getLastJobExecution("discreteRegisteredJob",
new JobParameters()));
}
@Test
public void testDefinesAndLaunchesLocalJob() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.batch.job.names:discreteLocalJob");
this.context.register(NamedJobConfigurationWithLocalJob.class, BatchAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class,
this.context.register(NamedJobConfigurationWithLocalJob.class,
BatchAutoConfiguration.class, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(JobLauncher.class));
@ -206,17 +207,17 @@ public class BatchAutoConfigurationTests {
protected static class NamedJobConfigurationWithRegisteredJob {
@Autowired
private JobRegistry jobRegistry;
@Autowired
private JobRepository jobRepository;
@Bean
public JobRegistryBeanPostProcessor registryProcessor() {
JobRegistryBeanPostProcessor processor = new JobRegistryBeanPostProcessor();
processor.setJobRegistry(jobRegistry);
processor.setJobRegistry(this.jobRegistry);
return processor;
}
@Bean
public Job discreteJob() {
AbstractJob job = new AbstractJob("discreteRegisteredJob") {
@ -241,13 +242,13 @@ public class BatchAutoConfigurationTests {
return job;
}
}
@EnableBatchProcessing
protected static class NamedJobConfigurationWithLocalJob {
@Autowired
private JobRepository jobRepository;
@Bean
public Job discreteJob() {
AbstractJob job = new AbstractJob("discreteLocalJob") {
@ -272,7 +273,7 @@ public class BatchAutoConfigurationTests {
return job;
}
}
@EnableBatchProcessing
protected static class JobConfiguration {
@Autowired

Loading…
Cancel
Save