This commit is contained in:
Michael Minella
2018-10-31 22:11:01 -05:00
parent d2bc2530cc
commit 90c88c52e6
29 changed files with 197 additions and 205 deletions

View File

@@ -43,7 +43,7 @@ import org.springframework.context.annotation.Configuration;
* @author Glenn Renfro
*/
@Configuration
@ConditionalOnProperty(name = "spring.cloud.task.batch.fail-on-job-failure", havingValue = "true", matchIfMissing = false)
@ConditionalOnProperty(name = "spring.cloud.task.batch.fail-on-job-failure", havingValue = "true")
@EnableConfigurationProperties(TaskBatchProperties.class)
@AutoConfigureBefore(BatchAutoConfiguration.class)
public class TaskJobLauncherAutoConfiguration {
@@ -51,15 +51,6 @@ public class TaskJobLauncherAutoConfiguration {
@Autowired
private TaskBatchProperties properties;
@Bean
@ConditionalOnMissingBean(JobRepository.class)
public JobRepository jobRepository(DataSource dataSource) throws Exception{
JobRepositoryFactoryBean factoryBean = new JobRepositoryFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
@Bean
public TaskJobLauncherCommandLineRunnerFactoryBean jobLauncherCommandLineRunner(JobLauncher jobLauncher,
JobExplorer jobExplorer, List<Job> jobs, JobRegistry jobRegistry, JobRepository jobRepository) {

View File

@@ -42,8 +42,6 @@ import org.springframework.batch.core.repository.JobExecutionAlreadyRunningExcep
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.repeat.RepeatCallback;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.boot.CommandLineRunner;
@@ -113,7 +111,7 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
public void run(String... args) throws JobExecutionException {
logger.info("Running default command line with: " + Arrays.asList(args));
launchJobFromProperties(StringUtils.splitArrayElementsIntoProperties(args, "="));
validateJobExecutions();
monitorJobExecutions();
}
protected void execute(Job job, JobParameters jobParameters)
@@ -161,69 +159,72 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
}
}
private void validateJobExecutions() {
private void monitorJobExecutions() {
RepeatTemplate template = new RepeatTemplate();
Date startDate = new Date();
template.iterate(new RepeatCallback() {
template.iterate(context -> {
public RepeatStatus doInIteration(RepeatContext context) throws InterruptedException {
List<JobExecution> failedJobExecutions = new ArrayList<>();
RepeatStatus repeatStatus = RepeatStatus.FINISHED;
for (JobExecution jobExecution : jobExecutionList) {
JobExecution currentJobExecution = taskJobExplorer.getJobExecution(jobExecution.getId());
BatchStatus batchStatus = currentJobExecution.getStatus();
if (batchStatus.isRunning()) {
repeatStatus = RepeatStatus.CONTINUABLE;
}
if (batchStatus.equals(BatchStatus.FAILED)) {
failedJobExecutions.add(jobExecution);
}
List<JobExecution> failedJobExecutions = new ArrayList<>();
RepeatStatus repeatStatus = RepeatStatus.FINISHED;
for (JobExecution jobExecution : jobExecutionList) {
JobExecution currentJobExecution = taskJobExplorer.getJobExecution(jobExecution.getId());
BatchStatus batchStatus = currentJobExecution.getStatus();
if (batchStatus.isRunning()) {
repeatStatus = RepeatStatus.CONTINUABLE;
}
Thread.sleep(taskBatchProperties.getFailOnJobFailurePollInterval());
if (repeatStatus.equals(RepeatStatus.FINISHED) && failedJobExecutions.size() > 0) {
throwJobFailedException(failedJobExecutions);
if (batchStatus.equals(BatchStatus.FAILED)) {
failedJobExecutions.add(jobExecution);
}
if (repeatStatus.isContinuable() && taskBatchProperties.getFailOnJobFailurewaitTime() != 0
&& (new Date()).getTime() - startDate.getTime() > taskBatchProperties.getFailOnJobFailurewaitTime()) {
throw new IllegalStateException("Not all jobs were completed " +
"within the time specified by spring.cloud.task.batch." +
"failOnJobFailurewaitTime.");
}
return repeatStatus;
}
Thread.sleep(taskBatchProperties.getFailOnJobFailurePollInterval());
if (repeatStatus.equals(RepeatStatus.FINISHED) && failedJobExecutions.size() > 0) {
throwJobFailedException(failedJobExecutions);
}
if (repeatStatus.isContinuable() && taskBatchProperties.getFailOnJobFailurewaitTime() != 0
&& (new Date()).getTime() - startDate.getTime() > taskBatchProperties.getFailOnJobFailurewaitTime()) {
throw new IllegalStateException("Not all jobs were completed " +
"within the time specified by spring.cloud.task.batch." +
"failOnJobFailurewaitTime.");
}
return repeatStatus;
});
}
public void throwJobFailedException(List<JobExecution> failedJobExecutions) {
String message = "The following Jobs have failed: \n";
private void throwJobFailedException(List<JobExecution> failedJobExecutions) {
StringBuilder message = new StringBuilder("The following Jobs have failed: \n");
for (JobExecution failedJobExecution : failedJobExecutions) {
message += String.format("Job %s failed during " +
"execution for jobId %s with jobExecutionId of %s \n",
message.append(String.format("Job %s failed during " +
"execution for job instance id %s with jobExecutionId of %s \n",
failedJobExecution.getJobInstance().getJobName(),
failedJobExecution.getJobId(), failedJobExecution.getId());
failedJobExecution.getJobId(), failedJobExecution.getId()));
}
logger.error(message);
throw new TaskException(message);
throw new TaskException(message.toString());
}
private JobParameters removeNonIdentifying(JobParameters parameters) {
Map<String, JobParameter> parameterMap = parameters.getParameters();
HashMap<String, JobParameter> copy = new HashMap<>(parameterMap);
for (Map.Entry<String, JobParameter> parameter : copy.entrySet()) {
if (!parameter.getValue().isIdentifying()) {
parameterMap.remove(parameter.getKey());
}
}
return new JobParameters(parameterMap);
}
private boolean isStoppedOrFailed(JobExecution execution) {
BatchStatus status = execution.getStatus();
return (status == BatchStatus.STOPPED || status == BatchStatus.FAILED);
}
private JobParameters merge(JobParameters parameters, JobParameters additionals) {
Map<String, JobParameter> merged = new HashMap<>();
merged.putAll(parameters.getParameters());

View File

@@ -42,6 +42,7 @@ import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.task.batch.configuration.TaskBatchProperties;
@@ -72,9 +73,6 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
@Autowired
private JobExplorer jobExplorer;
@Autowired
private BatchConfiguration batchConfigurer;
@Autowired
private PlatformTransactionManager transactionManager;
@@ -90,10 +88,9 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
@Before
public void init() {
batchConfigurer.clear();
this.jobs = new JobBuilderFactory(this.jobRepository);
this.steps = new StepBuilderFactory(this.jobRepository, this.transactionManager);
Tasklet tasklet = (contribution, chunkContext) -> null;
Tasklet tasklet = (contribution, chunkContext) -> RepeatStatus.FINISHED;
this.step = this.steps.get("step").tasklet(tasklet).build();
this.job = this.jobs.get("job").start(this.step).build();
this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, jobRepository, new TaskBatchProperties());
@@ -132,6 +129,7 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
}
@DirtiesContext
@Test
public void runDifferentInstances() throws Exception {
this.job = this.jobs.get("job")
@@ -162,10 +160,8 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2);
// try to re-run a failed execution
Executable executable = () -> {
this.runner.execute(this.job,
new JobParametersBuilder().addLong("run.id", 1L).toJobParameters());
};
Executable executable = () -> this.runner.execute(this.job,
new JobParametersBuilder().addLong("run.id", 1L).toJobParameters());
Throwable exception = assertThrows(JobRestartException.class, executable);
AssertionsForClassTypes.assertThat(exception.getMessage())
.isEqualTo("JobInstance already exists and is not restartable");
@@ -187,6 +183,7 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
}
@DirtiesContext
@Test
public void retryFailedExecutionWithDifferentNonIdentifyingParametersFromPreviousExecution()
throws Exception {
@@ -254,10 +251,6 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
this.jobRepository = this.jobRepositoryFactory.getObject();
}
public void clear() {
this.jobRepositoryFactory.clear();
}
@Override
public JobRepository getJobRepository() {
return this.jobRepository;

View File

@@ -70,7 +70,7 @@ public class TaskJobLauncherCommandLineRunnerTests {
private ConfigurableApplicationContext applicationContext;
private static final String DEFAULT_ERROR_MESSAGE = "The following Jobs have failed: \n" +
"Job jobA failed during execution for jobId 1 with jobExecutionId of 1 \n";
"Job jobA failed during execution for job instance id 1 with jobExecutionId of 1 \n";
@After
public void tearDown() {
@@ -146,9 +146,8 @@ public class TaskJobLauncherCommandLineRunnerTests {
validateContext();
assertThat(applicationContext.getBean(JobLauncherCommandLineRunner.class)).isNotNull();
Executable executable = () -> {
applicationContext.getBean(TaskJobLauncherCommandLineRunner.class);
};
Executable executable = () -> applicationContext.getBean(TaskJobLauncherCommandLineRunner.class);
Throwable exception = assertThrows(NoSuchBeanDefinitionException.class, executable);
assertThat(exception.getMessage()).isEqualTo("No qualifying bean of type " +
"'org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner' available");
@@ -168,9 +167,9 @@ public class TaskJobLauncherCommandLineRunnerTests {
}
private void validateForFail(String errorMessage, Class clazz, String [] enabledArgs) {
Executable executable = () -> {
this.applicationContext = SpringApplication
.run(new Class[] { clazz,PropertyPlaceholderAutoConfiguration.class}, enabledArgs);};
Executable executable = () -> this.applicationContext = SpringApplication
.run(new Class[] { clazz,PropertyPlaceholderAutoConfiguration.class}, enabledArgs);
Throwable exception = assertThrows(IllegalStateException.class, executable);
assertThat(exception.getCause().getMessage()).isEqualTo(errorMessage);
}

View File

@@ -56,7 +56,7 @@ public class PrefixTests {
@Test
public void testPrefix() {
this.applicationContext = SpringApplication.run(
JobConfiguration.class, new String[] { "--spring.cloud.task.tablePrefix=FOO_" });
JobConfiguration.class, "--spring.cloud.task.tablePrefix=FOO_");
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);

View File

@@ -68,7 +68,7 @@ import static org.junit.Assert.assertEquals;
*/
public class TaskBatchExecutionListenerTests {
public static final String[] ARGS = new String[] {};
private static final String[] ARGS = new String[] {};
private ConfigurableApplicationContext applicationContext;
@@ -89,35 +89,35 @@ public class TaskBatchExecutionListenerTests {
@Test(expected = AssertionError.class)
public void testNoAutoConfigurationEnabled() {
this.applicationContext = SpringApplication.run(JobConfiguration.class,
new String[] {"--spring.cloud.task.batch.listener.enabled=false"});
"--spring.cloud.task.batch.listener.enabled=false");
validateContext();
}
@Test(expected = AssertionError.class)
public void testNoAutoConfigurationEnable() {
this.applicationContext = SpringApplication.run(JobConfiguration.class ,
new String[] {"--spring.cloud.task.batch.listener.enable=false"});
"--spring.cloud.task.batch.listener.enable=false");
validateContext();
}
@Test(expected = AssertionError.class)
public void testNoAutoConfigurationBothDisabled() {
this.applicationContext = SpringApplication.run(JobConfiguration.class ,
new String[] {"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false"});
"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false");
validateContext();
}
@Test
public void testAutoConfigurationEnable() {
this.applicationContext = SpringApplication.run(JobConfiguration.class ,
new String[] {"--spring.cloud.task.batch.listener.enable=true"});
"--spring.cloud.task.batch.listener.enable=true");
validateContext();
}
@Test
public void testAutoConfigurationEnabled() {
this.applicationContext = SpringApplication.run(JobConfiguration.class ,
new String[] {"--spring.cloud.task.batch.listener.enabled=true"});
"--spring.cloud.task.batch.listener.enabled=true");
validateContext();
}
@@ -198,7 +198,7 @@ public class TaskBatchExecutionListenerTests {
@Test
public void testBatchExecutionListenerBeanPostProcessorWithJobNames() {
List jobNames = new ArrayList<String>(3);
List<String> jobNames = new ArrayList<>(3);
jobNames.add("job1");
jobNames.add("job2");
jobNames.add("TESTOBJECT");
@@ -215,7 +215,7 @@ public class TaskBatchExecutionListenerTests {
@Test
public void testBatchExecutionListenerBeanPostProcessorWithEmptyJobNames() {
TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor =
beanPostProcessor(Collections.<String>emptyList());
beanPostProcessor(Collections.emptyList());
SimpleJob testObject = new SimpleJob();
SimpleJob bean = (SimpleJob) beanPostProcessor.
@@ -226,8 +226,7 @@ public class TaskBatchExecutionListenerTests {
@Test(expected = IllegalArgumentException.class)
public void testBatchExecutionListenerBeanPostProcessorNullJobNames() {
TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor =
beanPostProcessor(null);
beanPostProcessor(null);
}
private TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor(