diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java index 6816d2c96a42..1220634b5cd9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.batch; +import javax.annotation.PostConstruct; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -41,7 +43,6 @@ import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobParametersNotFoundException; -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; @@ -112,6 +113,18 @@ public JobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExpl this.jobRepository = jobRepository; } + @PostConstruct + public void validate() { + if (StringUtils.hasText(this.jobNames)) { + String[] jobsToRun = this.jobNames.split(","); + for (String jobName : jobsToRun) { + if (!isLocalJob(jobName) && !isRegisteredJob(jobName)) { + throw new IllegalArgumentException("No job instances were found for job name [" + jobName + "]"); + } + } + } + } + public void setOrder(int order) { this.order = order; } @@ -162,6 +175,14 @@ protected void launchJobFromProperties(Properties properties) throws JobExecutio executeRegisteredJobs(jobParameters); } + private boolean isLocalJob(String jobName) { + return this.jobs.stream().anyMatch((job) -> job.getName().equals(jobName)); + } + + private boolean isRegisteredJob(String jobName) { + return this.jobRegistry != null && this.jobRegistry.getJobNames().contains(jobName); + } + private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException { for (Job job : this.jobs) { if (StringUtils.hasText(this.jobNames)) { @@ -179,19 +200,10 @@ private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecut if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) { String[] jobsToRun = this.jobNames.split(","); for (String jobName : jobsToRun) { - try { + if (isRegisteredJob(jobName) && !isLocalJob(jobName)) { Job job = this.jobRegistry.getJob(jobName); - if (this.jobs.contains(job)) { - continue; - } execute(job, jobParameters); } - catch (NoSuchJobException ex) { - logger.debug(LogMessage.format("No job found in registry for job name: %s", jobName)); - if(this.jobExplorer != null && this.jobExplorer.getLastJobInstance(jobName) == null) { - throw ex; - } - } } } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java index 5418b8a298a9..9a00e5925e66 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java @@ -38,7 +38,6 @@ import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.job.AbstractJob; import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -72,7 +71,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; /** @@ -82,7 +80,7 @@ * @author Stephane Nicoll * @author Vedran Pavic * @author Kazuki Shimizu - * @author Akshay Dubey + * @author Scott Frederick */ @ExtendWith(OutputCaptureExtension.class) class BatchAutoConfigurationTests { @@ -378,18 +376,13 @@ void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredBatchInit } @Test - void testExecuteLocalAndNonConfiguredJob() { - this.contextRunner - .withUserConfiguration(NamedJobConfigurationWithLocalJob.class, EmbeddedDataSourceConfiguration.class) - .withPropertyValues("spring.batch.job.names:discreteLocalJob,nonConfiguredJob") - .run((context) -> { - assertThat(context).hasSingleBean(JobLauncher.class); - assertThrows(NoSuchJobException.class,()->{ - context.getBean(JobLauncherApplicationRunner.class).run(); - }); - assertThat(context.getBean(JobRepository.class) - .getLastJobExecution("discreteLocalJob", new JobParameters())).isNotNull(); - }); + void nonConfiguredJobThrowsException() { + this.contextRunner.withUserConfiguration(JobConfiguration.class, EmbeddedDataSourceConfiguration.class) + .withPropertyValues("spring.batch.job.names:nonConfiguredJob") + .run((context) -> assertThat(context).hasFailed() + .getFailure() + .getRootCause() + .hasMessageContaining("nonConfiguredJob")); } @Configuration(proxyBeanMethods = false)