Browse Source

Merge pull request #36060 from itsAkshayDubey

* pr/36060:
  Polish "Fail fast if job name does not exist"
  Fail fast if job name does not exist

Closes gh-36060
pull/36620/head
Stephane Nicoll 2 years ago
parent
commit
45f685f3fc
  1. 41
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java
  2. 50
      spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java

41
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java

@ -41,11 +41,11 @@ import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobParametersNotFoundException; 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.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException; import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
@ -66,9 +66,11 @@ import org.springframework.util.StringUtils;
* @author Jean-Pierre Bergamin * @author Jean-Pierre Bergamin
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Akshay Dubey
* @since 2.3.0 * @since 2.3.0
*/ */
public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered, ApplicationEventPublisherAware { public class JobLauncherApplicationRunner
implements ApplicationRunner, InitializingBean, Ordered, ApplicationEventPublisherAware {
/** /**
* The default order for the command line runner. * The default order for the command line runner.
@ -111,6 +113,17 @@ public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered,
this.jobRepository = jobRepository; this.jobRepository = jobRepository;
} }
@Override
public void afterPropertiesSet() {
if (StringUtils.hasText(this.jobNames)) {
for (String jobName : jobsToRun()) {
if (!isLocalJob(jobName) && !isRegisteredJob(jobName)) {
throw new IllegalArgumentException("No job found with name '" + jobName + "'");
}
}
}
}
public void setOrder(int order) { public void setOrder(int order) {
this.order = order; this.order = order;
} }
@ -161,10 +174,18 @@ public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered,
executeRegisteredJobs(jobParameters); 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 { private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException {
for (Job job : this.jobs) { for (Job job : this.jobs) {
if (StringUtils.hasText(this.jobNames)) { if (StringUtils.hasText(this.jobNames)) {
String[] jobsToRun = this.jobNames.split(","); String[] jobsToRun = jobsToRun();
if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) { if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) {
logger.debug(LogMessage.format("Skipped job: %s", job.getName())); logger.debug(LogMessage.format("Skipped job: %s", job.getName()));
continue; continue;
@ -176,18 +197,12 @@ public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered,
private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException { private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException {
if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) { if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) {
String[] jobsToRun = this.jobNames.split(","); String[] jobsToRun = jobsToRun();
for (String jobName : jobsToRun) { for (String jobName : jobsToRun) {
try { if (!isLocalJob(jobName)) {
Job job = this.jobRegistry.getJob(jobName); Job job = this.jobRegistry.getJob(jobName);
if (this.jobs.contains(job)) {
continue;
}
execute(job, jobParameters); execute(job, jobParameters);
} }
catch (NoSuchJobException ex) {
logger.debug(LogMessage.format("No job found in registry for job name: %s", jobName));
}
} }
} }
} }
@ -246,4 +261,8 @@ public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered,
return new JobParameters(merged); return new JobParameters(merged);
} }
private String[] jobsToRun() {
return this.jobNames.split(",");
}
} }

50
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java

@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.batch; package org.springframework.boot.autoconfigure.batch;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -71,6 +72,8 @@ import org.springframework.transaction.PlatformTransactionManager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
@ -374,6 +377,53 @@ class BatchAutoConfigurationTests {
.hasBean("customInitializer")); .hasBean("customInitializer"));
} }
@Test
void whenTheUserDefinesAJobNameAsJobInstanceValidates() {
JobLauncherApplicationRunner runner = createInstance("another");
runner.setJobs(Collections.singletonList(mockJob("test")));
runner.setJobNames("test");
runner.afterPropertiesSet();
}
@Test
void whenTheUserDefinesAJobNameAsRegisteredJobValidates() {
JobLauncherApplicationRunner runner = createInstance("test");
runner.setJobNames("test");
runner.afterPropertiesSet();
}
@Test
void whenTheUserDefinesAJobNameThatDoesNotExistWithJobInstancesFailsFast() {
JobLauncherApplicationRunner runner = createInstance();
runner.setJobs(Arrays.asList(mockJob("one"), mockJob("two")));
runner.setJobNames("three");
assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet)
.withMessage("No job found with name 'three'");
}
@Test
void whenTheUserDefinesAJobNameThatDoesNotExistWithRegisteredJobFailsFast() {
JobLauncherApplicationRunner runner = createInstance("one", "two");
runner.setJobNames("three");
assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet)
.withMessage("No job found with name 'three'");
}
private JobLauncherApplicationRunner createInstance(String... registeredJobNames) {
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(mock(JobLauncher.class),
mock(JobExplorer.class), mock(JobRepository.class));
JobRegistry jobRegistry = mock(JobRegistry.class);
given(jobRegistry.getJobNames()).willReturn(Arrays.asList(registeredJobNames));
runner.setJobRegistry(jobRegistry);
return runner;
}
private Job mockJob(String name) {
Job job = mock(Job.class);
given(job.getName()).willReturn(name);
return job;
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
protected static class BatchDataSourceConfiguration { protected static class BatchDataSourceConfiguration {

Loading…
Cancel
Save