Remove support for multiple batch jobs

Closes gh-25373
This commit is contained in:
Madhura Bhave
2022-06-10 14:34:02 -07:00
parent fabe0637cd
commit 55d6a87fef
5 changed files with 200 additions and 45 deletions

View File

@@ -24,6 +24,7 @@ import javax.sql.DataSource;
import jakarta.persistence.EntityManagerFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
@@ -31,6 +32,8 @@ import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.DuplicateJobException;
import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
@@ -39,7 +42,9 @@ 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.repository.JobRepository;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.DefaultApplicationArguments;
@@ -60,6 +65,7 @@ import org.springframework.boot.sql.init.DatabaseInitializationSettings;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@@ -138,11 +144,11 @@ class BatchAutoConfigurationTests {
}
@Test
void testDefinesAndLaunchesNamedJob() {
void testDefinesAndLaunchesNamedRegisteredJob() {
this.contextRunner
.withUserConfiguration(NamedJobConfigurationWithRegisteredJob.class,
EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.batch.job.names:discreteRegisteredJob").run((context) -> {
.withPropertyValues("spring.batch.job.name:discreteRegisteredJob").run((context) -> {
assertThat(context).hasSingleBean(JobLauncher.class);
context.getBean(JobLauncherApplicationRunner.class).run();
assertThat(context.getBean(JobRepository.class).getLastJobExecution("discreteRegisteredJob",
@@ -150,11 +156,46 @@ class BatchAutoConfigurationTests {
});
}
@Test
void testRegisteredAndLocalJob() {
this.contextRunner
.withUserConfiguration(NamedJobConfigurationWithRegisteredAndLocalJob.class,
EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.batch.job.name:discreteRegisteredJob").run((context) -> {
assertThat(context).hasSingleBean(JobLauncher.class);
context.getBean(JobLauncherApplicationRunner.class).run();
assertThat(context.getBean(JobRepository.class)
.getLastJobExecution("discreteRegisteredJob", new JobParameters()).getStatus())
.isEqualTo(BatchStatus.COMPLETED);
});
}
@Test
void testDefinesAndLaunchesLocalJob() {
this.contextRunner
.withUserConfiguration(NamedJobConfigurationWithLocalJob.class, EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.batch.job.names:discreteLocalJob").run((context) -> {
.withPropertyValues("spring.batch.job.name:discreteLocalJob").run((context) -> {
assertThat(context).hasSingleBean(JobLauncher.class);
context.getBean(JobLauncherApplicationRunner.class).run();
assertThat(context.getBean(JobRepository.class).getLastJobExecution("discreteLocalJob",
new JobParameters())).isNotNull();
});
}
@Test
void testMultipleJobsAndNoJobName() {
this.contextRunner.withUserConfiguration(MultipleJobConfiguration.class, EmbeddedDataSourceConfiguration.class)
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure().getCause().getMessage())
.contains("Job name must be specified in case of multiple jobs");
});
}
@Test
void testMultipleJobsAndJobName() {
this.contextRunner.withUserConfiguration(MultipleJobConfiguration.class, EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.batch.job.name:discreteLocalJob").run((context) -> {
assertThat(context).hasSingleBean(JobLauncher.class);
context.getBean(JobLauncherApplicationRunner.class).run();
assertThat(context.getBean(JobRepository.class).getLastJobExecution("discreteLocalJob",
@@ -395,18 +436,15 @@ class BatchAutoConfigurationTests {
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
static class NamedJobConfigurationWithRegisteredJob {
@Autowired
private JobRegistry jobRegistry;
static class NamedJobConfigurationWithRegisteredAndLocalJob {
@Autowired
private JobRepository jobRepository;
@Bean
JobRegistryBeanPostProcessor registryProcessor() {
static JobRegistryBeanPostProcessor registryProcessor(JobRegistry jobRegistry) {
JobRegistryBeanPostProcessor processor = new JobRegistryBeanPostProcessor();
processor.setJobRegistry(this.jobRegistry);
processor.setJobRegistry(jobRegistry);
return processor;
}
@@ -414,6 +452,8 @@ class BatchAutoConfigurationTests {
Job discreteJob() {
AbstractJob job = new AbstractJob("discreteRegisteredJob") {
private static int count = 0;
@Override
public Collection<String> getStepNames() {
return Collections.emptySet();
@@ -426,7 +466,13 @@ class BatchAutoConfigurationTests {
@Override
protected void doExecute(JobExecution execution) {
execution.setStatus(BatchStatus.COMPLETED);
if (count == 0) {
execution.setStatus(BatchStatus.COMPLETED);
}
else {
execution.setStatus(BatchStatus.FAILED);
}
count++;
}
};
job.setJobRepository(this.jobRepository);
@@ -435,6 +481,75 @@ class BatchAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
static class NamedJobConfigurationWithRegisteredJob {
@Bean
static BeanPostProcessor registryProcessor(ApplicationContext applicationContext) {
return new NamedJobJobRegistryBeanPostProcessor(applicationContext);
}
}
static class NamedJobJobRegistryBeanPostProcessor implements BeanPostProcessor {
private final ApplicationContext applicationContext;
NamedJobJobRegistryBeanPostProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof JobRegistry jobRegistry) {
try {
jobRegistry.register(getJobFactory());
}
catch (DuplicateJobException ex) {
}
}
return bean;
}
private JobFactory getJobFactory() {
JobRepository jobRepository = this.applicationContext.getBean(JobRepository.class);
return new JobFactory() {
@Override
public Job createJob() {
AbstractJob job = new AbstractJob("discreteRegisteredJob") {
@Override
public Collection<String> getStepNames() {
return Collections.emptySet();
}
@Override
public Step getStep(String stepName) {
return null;
}
@Override
protected void doExecute(JobExecution execution) {
execution.setStatus(BatchStatus.COMPLETED);
}
};
job.setJobRepository(jobRepository);
return job;
}
@Override
public String getJobName() {
return "discreteRegisteredJob";
}
};
}
}
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
static class NamedJobConfigurationWithLocalJob {
@@ -467,6 +582,43 @@ class BatchAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
static class MultipleJobConfiguration {
@Autowired
private JobRepository jobRepository;
@Bean
Job discreteJob() {
AbstractJob job = new AbstractJob("discreteLocalJob") {
@Override
public Collection<String> getStepNames() {
return Collections.emptySet();
}
@Override
public Step getStep(String stepName) {
return null;
}
@Override
protected void doExecute(JobExecution execution) {
execution.setStatus(BatchStatus.COMPLETED);
}
};
job.setJobRepository(this.jobRepository);
return job;
}
@Bean
Job job2() {
return Mockito.mock(Job.class);
}
}
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
static class JobConfiguration {