Skip to content

Commit 45f685f

Browse files
committed
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
2 parents a5d5908 + 854c162 commit 45f685f

File tree

2 files changed

+80
-11
lines changed

2 files changed

+80
-11
lines changed

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

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@
4141
import org.springframework.batch.core.explore.JobExplorer;
4242
import org.springframework.batch.core.launch.JobLauncher;
4343
import org.springframework.batch.core.launch.JobParametersNotFoundException;
44-
import org.springframework.batch.core.launch.NoSuchJobException;
4544
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
4645
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
4746
import org.springframework.batch.core.repository.JobRepository;
4847
import org.springframework.batch.core.repository.JobRestartException;
48+
import org.springframework.beans.factory.InitializingBean;
4949
import org.springframework.beans.factory.annotation.Autowired;
5050
import org.springframework.boot.ApplicationArguments;
5151
import org.springframework.boot.ApplicationRunner;
@@ -66,9 +66,11 @@
6666
* @author Jean-Pierre Bergamin
6767
* @author Mahmoud Ben Hassine
6868
* @author Stephane Nicoll
69+
* @author Akshay Dubey
6970
* @since 2.3.0
7071
*/
71-
public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered, ApplicationEventPublisherAware {
72+
public class JobLauncherApplicationRunner
73+
implements ApplicationRunner, InitializingBean, Ordered, ApplicationEventPublisherAware {
7274

7375
/**
7476
* The default order for the command line runner.
@@ -111,6 +113,17 @@ public JobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExpl
111113
this.jobRepository = jobRepository;
112114
}
113115

116+
@Override
117+
public void afterPropertiesSet() {
118+
if (StringUtils.hasText(this.jobNames)) {
119+
for (String jobName : jobsToRun()) {
120+
if (!isLocalJob(jobName) && !isRegisteredJob(jobName)) {
121+
throw new IllegalArgumentException("No job found with name '" + jobName + "'");
122+
}
123+
}
124+
}
125+
}
126+
114127
public void setOrder(int order) {
115128
this.order = order;
116129
}
@@ -161,10 +174,18 @@ protected void launchJobFromProperties(Properties properties) throws JobExecutio
161174
executeRegisteredJobs(jobParameters);
162175
}
163176

177+
private boolean isLocalJob(String jobName) {
178+
return this.jobs.stream().anyMatch((job) -> job.getName().equals(jobName));
179+
}
180+
181+
private boolean isRegisteredJob(String jobName) {
182+
return this.jobRegistry != null && this.jobRegistry.getJobNames().contains(jobName);
183+
}
184+
164185
private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException {
165186
for (Job job : this.jobs) {
166187
if (StringUtils.hasText(this.jobNames)) {
167-
String[] jobsToRun = this.jobNames.split(",");
188+
String[] jobsToRun = jobsToRun();
168189
if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) {
169190
logger.debug(LogMessage.format("Skipped job: %s", job.getName()));
170191
continue;
@@ -176,18 +197,12 @@ private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionEx
176197

177198
private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException {
178199
if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) {
179-
String[] jobsToRun = this.jobNames.split(",");
200+
String[] jobsToRun = jobsToRun();
180201
for (String jobName : jobsToRun) {
181-
try {
202+
if (!isLocalJob(jobName)) {
182203
Job job = this.jobRegistry.getJob(jobName);
183-
if (this.jobs.contains(job)) {
184-
continue;
185-
}
186204
execute(job, jobParameters);
187205
}
188-
catch (NoSuchJobException ex) {
189-
logger.debug(LogMessage.format("No job found in registry for job name: %s", jobName));
190-
}
191206
}
192207
}
193208
}
@@ -246,4 +261,8 @@ private JobParameters merge(JobParameters parameters, JobParameters additionals)
246261
return new JobParameters(merged);
247262
}
248263

264+
private String[] jobsToRun() {
265+
return this.jobNames.split(",");
266+
}
267+
249268
}

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.batch;
1818

19+
import java.util.Arrays;
1920
import java.util.Collection;
2021
import java.util.Collections;
2122

@@ -71,6 +72,8 @@
7172

7273
import static org.assertj.core.api.Assertions.assertThat;
7374
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
75+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
76+
import static org.mockito.BDDMockito.given;
7477
import static org.mockito.Mockito.mock;
7578

7679
/**
@@ -374,6 +377,53 @@ void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredBatchInit
374377
.hasBean("customInitializer"));
375378
}
376379

380+
@Test
381+
void whenTheUserDefinesAJobNameAsJobInstanceValidates() {
382+
JobLauncherApplicationRunner runner = createInstance("another");
383+
runner.setJobs(Collections.singletonList(mockJob("test")));
384+
runner.setJobNames("test");
385+
runner.afterPropertiesSet();
386+
}
387+
388+
@Test
389+
void whenTheUserDefinesAJobNameAsRegisteredJobValidates() {
390+
JobLauncherApplicationRunner runner = createInstance("test");
391+
runner.setJobNames("test");
392+
runner.afterPropertiesSet();
393+
}
394+
395+
@Test
396+
void whenTheUserDefinesAJobNameThatDoesNotExistWithJobInstancesFailsFast() {
397+
JobLauncherApplicationRunner runner = createInstance();
398+
runner.setJobs(Arrays.asList(mockJob("one"), mockJob("two")));
399+
runner.setJobNames("three");
400+
assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet)
401+
.withMessage("No job found with name 'three'");
402+
}
403+
404+
@Test
405+
void whenTheUserDefinesAJobNameThatDoesNotExistWithRegisteredJobFailsFast() {
406+
JobLauncherApplicationRunner runner = createInstance("one", "two");
407+
runner.setJobNames("three");
408+
assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet)
409+
.withMessage("No job found with name 'three'");
410+
}
411+
412+
private JobLauncherApplicationRunner createInstance(String... registeredJobNames) {
413+
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(mock(JobLauncher.class),
414+
mock(JobExplorer.class), mock(JobRepository.class));
415+
JobRegistry jobRegistry = mock(JobRegistry.class);
416+
given(jobRegistry.getJobNames()).willReturn(Arrays.asList(registeredJobNames));
417+
runner.setJobRegistry(jobRegistry);
418+
return runner;
419+
}
420+
421+
private Job mockJob(String name) {
422+
Job job = mock(Job.class);
423+
given(job.getName()).willReturn(name);
424+
return job;
425+
}
426+
377427
@Configuration(proxyBeanMethods = false)
378428
protected static class BatchDataSourceConfiguration {
379429

0 commit comments

Comments
 (0)