Allows failed batch apps to set exit code of task app.
resolves #201 Please enter the commit message for your changes. Lines starting Cleanup Removed taskProperties from TaskBatchAutoConfiguration
This commit is contained in:
committed by
Michael Minella
parent
b6f6d68385
commit
cd4dbe6a93
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -56,14 +56,11 @@ public class TaskBatchAutoConfiguration {
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private TaskProperties taskProperties;
|
||||
|
||||
@Bean
|
||||
public TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(TaskExplorer taskExplorer) {
|
||||
TaskConfigurer taskConfigurer = null;
|
||||
if(!context.getBeansOfType(TaskConfigurer.class).isEmpty()) {
|
||||
taskConfigurer = context.getBean(TaskConfigurer.class);
|
||||
if(!this.context.getBeansOfType(TaskConfigurer.class).isEmpty()) {
|
||||
taskConfigurer = this.context.getBean(TaskConfigurer.class);
|
||||
}
|
||||
if(taskConfigurer != null && taskConfigurer.getTaskDataSource() != null) {
|
||||
return new TaskBatchExecutionListenerFactoryBean(
|
||||
@@ -74,6 +71,5 @@ public class TaskBatchAutoConfiguration {
|
||||
return new TaskBatchExecutionListenerFactoryBean(null, taskExplorer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.configuration;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Establish properties to be used for how Tasks work with
|
||||
* Spring Batch.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.cloud.task.batch")
|
||||
public class TaskBatchProperties {
|
||||
|
||||
/**
|
||||
* Comma-separated list of job names to execute on startup (for instance,
|
||||
* `job1,job2`). By default, all Jobs found in the context are executed.
|
||||
*/
|
||||
private String jobNames = "";
|
||||
|
||||
public String getJobNames() {
|
||||
return this.jobNames;
|
||||
}
|
||||
|
||||
public void setJobNames(String jobNames) {
|
||||
this.jobNames = jobNames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Provides auto configuration for the
|
||||
* {@link org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner}.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name = "spring.cloud.task.batch.commandLineRunnerEnabled", havingValue = "true", matchIfMissing = false)
|
||||
@EnableConfigurationProperties(TaskBatchProperties.class)
|
||||
public class TaskJobLauncherAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private TaskBatchProperties properties;
|
||||
|
||||
@Bean
|
||||
public TaskJobLauncherCommandLineRunnerFactoryBean jobLauncherCommandLineRunner(JobLauncher jobLauncher,
|
||||
JobExplorer jobExplorer, List<Job> jobs, JobRegistry jobRegistry) {
|
||||
TaskJobLauncherCommandLineRunnerFactoryBean taskJobLauncherCommandLineRunner = new TaskJobLauncherCommandLineRunnerFactoryBean(
|
||||
jobLauncher, jobExplorer, jobs, this.properties.getJobNames(), jobRegistry);
|
||||
return taskJobLauncherCommandLineRunner;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Factory bean for creating an instance of {@link TaskJobLauncherCommandLineRunner}.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean<TaskJobLauncherCommandLineRunner> {
|
||||
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
private JobExplorer jobExplorer;
|
||||
|
||||
private List<Job> jobs;
|
||||
|
||||
private String jobNames;
|
||||
|
||||
private JobRegistry jobRegistry;
|
||||
|
||||
public TaskJobLauncherCommandLineRunnerFactoryBean(JobLauncher jobLauncher,
|
||||
JobExplorer jobExplorer, List<Job> jobs, String jobNames,
|
||||
JobRegistry jobRegistry) {
|
||||
this.jobLauncher = jobLauncher;
|
||||
this.jobExplorer = jobExplorer;
|
||||
Assert.notEmpty(jobs, "jobs must not be null nor empty");
|
||||
this.jobs = jobs;
|
||||
this.jobNames = jobNames;
|
||||
this.jobRegistry = jobRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskJobLauncherCommandLineRunner getObject() throws Exception {
|
||||
TaskJobLauncherCommandLineRunner taskJobLauncherCommandLineRunner =
|
||||
new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer);
|
||||
taskJobLauncherCommandLineRunner.setJobs(this.jobs);
|
||||
if(StringUtils.hasText(this.jobNames)) {
|
||||
taskJobLauncherCommandLineRunner.setJobNames(this.jobNames);
|
||||
}
|
||||
taskJobLauncherCommandLineRunner.setJobRegistry(this.jobRegistry);
|
||||
return taskJobLauncherCommandLineRunner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return TaskJobLauncherCommandLineRunner.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.handler;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobExecutionException;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.JobParametersInvalidException;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
|
||||
import org.springframework.batch.core.converter.JobParametersConverter;
|
||||
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.JobRestartException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.autoconfigure.batch.JobExecutionEvent;
|
||||
import org.springframework.cloud.task.listener.TaskException;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link CommandLineRunner} to {@link JobLauncher launch} Spring Batch jobs. Runs all
|
||||
* jobs in the surrounding context by default and throw an exception upon the
|
||||
* first job that returns an {@link ExitStatus} of FAILED.
|
||||
* Can also be used to launch a specific job by providing a jobName. The
|
||||
* TaskJobLaunchercommandLineRunner takes the place of the
|
||||
* {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner}
|
||||
* when it is in use.
|
||||
*
|
||||
* @author Glenn Renfro
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class TaskJobLauncherCommandLineRunner implements CommandLineRunner, Ordered, ApplicationEventPublisherAware{
|
||||
/**
|
||||
* The default order for the command line runner.
|
||||
*/
|
||||
public static final int DEFAULT_ORDER = 0;
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(TaskJobLauncherCommandLineRunner.class);
|
||||
|
||||
private JobParametersConverter converter = new DefaultJobParametersConverter();
|
||||
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
private JobRegistry jobRegistry;
|
||||
|
||||
private JobExplorer jobExplorer;
|
||||
|
||||
private String jobNames;
|
||||
|
||||
private Collection<Job> jobs = Collections.emptySet();
|
||||
|
||||
private int order = DEFAULT_ORDER;
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher,
|
||||
JobExplorer jobExplorer) {
|
||||
this.jobLauncher = jobLauncher;
|
||||
this.jobExplorer = jobExplorer;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
public void setJobRegistry(JobRegistry jobRegistry) {
|
||||
this.jobRegistry = jobRegistry;
|
||||
}
|
||||
|
||||
public void setJobNames(String jobNames) {
|
||||
this.jobNames = jobNames;
|
||||
}
|
||||
|
||||
public void setJobParametersConverter(JobParametersConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public void setJobs(Collection<Job> jobs) {
|
||||
this.jobs = jobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws JobExecutionException {
|
||||
logger.info("Running default command line with: " + Arrays.asList(args));
|
||||
launchJobFromProperties(StringUtils.splitArrayElementsIntoProperties(args, "="));
|
||||
}
|
||||
|
||||
protected void launchJobFromProperties(Properties properties)
|
||||
throws JobExecutionException {
|
||||
JobParameters jobParameters = this.converter.getJobParameters(properties);
|
||||
executeLocalJobs(jobParameters);
|
||||
executeRegisteredJobs(jobParameters);
|
||||
}
|
||||
|
||||
private void executeRegisteredJobs(JobParameters jobParameters)
|
||||
throws JobExecutionException {
|
||||
if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) {
|
||||
String[] jobsToRun = this.jobNames.split(",");
|
||||
for (String jobName : jobsToRun) {
|
||||
try {
|
||||
Job job = this.jobRegistry.getJob(jobName);
|
||||
if (this.jobs.contains(job)) {
|
||||
continue;
|
||||
}
|
||||
execute(job, jobParameters);
|
||||
}
|
||||
catch (NoSuchJobException ex) {
|
||||
logger.debug("No job found in registry for job name: " + jobName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void execute(Job job, JobParameters jobParameters)
|
||||
throws JobExecutionAlreadyRunningException, JobRestartException,
|
||||
JobInstanceAlreadyCompleteException, JobParametersInvalidException,
|
||||
JobParametersNotFoundException {
|
||||
JobParameters nextParameters = new JobParametersBuilder(jobParameters,
|
||||
this.jobExplorer).getNextJobParameters(job).toJobParameters();
|
||||
JobExecution execution = this.jobLauncher.run(job, nextParameters);
|
||||
if (this.publisher != null) {
|
||||
this.publisher.publishEvent(new JobExecutionEvent(execution));
|
||||
}
|
||||
if(execution.getExitStatus().getExitCode().equals(ExitStatus.FAILED.getExitCode())) {
|
||||
String message = String.format("Job %s failed during " +
|
||||
"execution for jobId %s with jobExecutionId of %s",
|
||||
execution.getJobInstance().getJobName(),
|
||||
execution.getJobId(), execution.getId());
|
||||
logger.error(message);
|
||||
throw new TaskException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeLocalJobs(JobParameters jobParameters)
|
||||
throws JobExecutionException {
|
||||
for (Job job : this.jobs) {
|
||||
if (StringUtils.hasText(this.jobNames)) {
|
||||
String[] jobsToRun = this.jobNames.split(",");
|
||||
if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) {
|
||||
logger.debug("Skipped job: " + job.getName());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
execute(job, jobParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration,org.springframework.cloud.task.batch.configuration.TaskJobLauncherAutoConfiguration
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner;
|
||||
import org.springframework.cloud.task.batch.listener.TaskBatchExecutionListenerTests;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class TaskJobLauncherAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().
|
||||
withUserConfiguration(TaskBatchExecutionListenerTests.JobConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedDataSourceConfiguration.class,
|
||||
BatchAutoConfiguration.class,
|
||||
TaskJobLauncherAutoConfiguration.class);
|
||||
|
||||
@Test
|
||||
public void testAutoBuiltDataSourceWithTaskJobLauncherCLR() {
|
||||
this.contextRunner.
|
||||
withPropertyValues("spring.cloud.task.batch.commandLineRunnerEnabled=true").
|
||||
run(context -> {
|
||||
assertThat(context).hasSingleBean(TaskJobLauncherCommandLineRunner.class);
|
||||
assertThat(context).doesNotHaveBean(JobLauncherCommandLineRunner.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoBuiltDataSourceWithTaskJobLauncherCLRDisabled() {
|
||||
this.contextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(JobLauncherCommandLineRunner.class);
|
||||
assertThat(context).doesNotHaveBean(TaskJobLauncherCommandLineRunner.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.handler;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.launch.support.RunIdIncrementer;
|
||||
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.task.listener.TaskException;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = {TaskJobLauncherCommandLineRunnerCoreTests.BatchConfiguration.class})
|
||||
public class TaskJobLauncherCommandLineRunnerCoreTests {
|
||||
|
||||
@Autowired
|
||||
private JobRepository jobRepository;
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
private JobExplorer jobExplorer;
|
||||
|
||||
@Autowired
|
||||
PlatformTransactionManager transactionManager;
|
||||
|
||||
private TaskJobLauncherCommandLineRunner runner;
|
||||
|
||||
private JobBuilderFactory jobs;
|
||||
|
||||
private StepBuilderFactory steps;
|
||||
|
||||
private Job job;
|
||||
|
||||
private Step step;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
this.jobs = new JobBuilderFactory(this.jobRepository);
|
||||
this.steps = new StepBuilderFactory(this.jobRepository, this.transactionManager);
|
||||
Tasklet tasklet = (contribution, chunkContext) -> null;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@DirtiesContext
|
||||
@Test
|
||||
public void basicExecution() throws Exception {
|
||||
this.runner.execute(this.job, new JobParameters());
|
||||
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
|
||||
this.runner.execute(this.job,
|
||||
new JobParametersBuilder().addLong("id", 1L).toJobParameters());
|
||||
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2);
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
@Test
|
||||
public void incrementExistingExecution() throws Exception {
|
||||
this.job = this.jobs.get("job").start(this.step)
|
||||
.incrementer(new RunIdIncrementer()).build();
|
||||
this.runner.execute(this.job, new JobParameters());
|
||||
this.runner.execute(this.job, new JobParameters());
|
||||
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2);
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
@Test
|
||||
public void retryFailedExecution() throws Exception {
|
||||
this.job = this.jobs.get("job")
|
||||
.start(this.steps.get("step").tasklet(throwingTasklet()).build())
|
||||
.incrementer(new RunIdIncrementer()).build();
|
||||
runFailedJob(new JobParameters());
|
||||
runFailedJob(new JobParameters());
|
||||
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
@Test
|
||||
public void retryFailedExecutionOnNonRestartableJob() throws Exception {
|
||||
this.job = this.jobs.get("job").preventRestart()
|
||||
.start(this.steps.get("step").tasklet(throwingTasklet()).build())
|
||||
.incrementer(new RunIdIncrementer()).build();
|
||||
runFailedJob(new JobParameters());
|
||||
runFailedJob(new JobParameters());
|
||||
// A failed job that is not restartable does not re-use the job params of
|
||||
// the last execution, but creates a new job instance when running it again.
|
||||
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2);
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
@Test
|
||||
public void retryFailedExecutionWithNonIdentifyingParameters() throws Exception {
|
||||
this.job = this.jobs.get("job")
|
||||
.start(this.steps.get("step").tasklet(throwingTasklet()).build())
|
||||
.incrementer(new RunIdIncrementer()).build();
|
||||
JobParameters jobParameters = new JobParametersBuilder().addLong("id", 1L, false)
|
||||
.addLong("foo", 2L, false).toJobParameters();
|
||||
runFailedJob(new JobParameters());
|
||||
runFailedJob(new JobParameters());
|
||||
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
|
||||
}
|
||||
|
||||
private Tasklet throwingTasklet() {
|
||||
return (contribution, chunkContext) -> {
|
||||
throw new RuntimeException("Planned");
|
||||
};
|
||||
}
|
||||
|
||||
private void runFailedJob(JobParameters jobParameters) throws Exception {
|
||||
boolean isExceptionThrown = false;
|
||||
try {
|
||||
this.runner.execute(this.job, new JobParameters());
|
||||
}
|
||||
catch (TaskException taskException) {
|
||||
isExceptionThrown = true;
|
||||
}
|
||||
assertThat(isExceptionThrown).isTrue();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
protected static class BatchConfiguration implements BatchConfigurer {
|
||||
|
||||
private ResourcelessTransactionManager transactionManager =
|
||||
new ResourcelessTransactionManager();
|
||||
|
||||
private JobRepository jobRepository;
|
||||
|
||||
private MapJobRepositoryFactoryBean jobRepositoryFactory =
|
||||
new MapJobRepositoryFactoryBean(
|
||||
this.transactionManager);
|
||||
|
||||
public BatchConfiguration() throws Exception {
|
||||
this.jobRepository = this.jobRepositoryFactory.getObject();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.jobRepositoryFactory.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobRepository getJobRepository() {
|
||||
return this.jobRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformTransactionManager getTransactionManager() {
|
||||
return this.transactionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobLauncher getJobLauncher() {
|
||||
SimpleJobLauncher launcher = new SimpleJobLauncher();
|
||||
launcher.setJobRepository(this.jobRepository);
|
||||
launcher.setTaskExecutor(new SyncTaskExecutor());
|
||||
return launcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobExplorer getJobExplorer() throws Exception {
|
||||
return new MapJobExplorerFactoryBean(this.jobRepositoryFactory).getObject();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.task.batch.handler;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration;
|
||||
import org.springframework.cloud.task.batch.configuration.TaskJobLauncherAutoConfiguration;
|
||||
import org.springframework.cloud.task.configuration.EnableTask;
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.cloud.task.repository.TaskExplorer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class TaskJobLauncherCommandLineRunnerTests {
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (this.applicationContext != null) {
|
||||
this.applicationContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskJobLauncherCLRSuccessFail() {
|
||||
String[] enabledArgs = new String[] { "--spring.cloud.task.batch.commandLineRunnerEnabled=true" };
|
||||
boolean isExceptionThrown = false;
|
||||
try {
|
||||
this.applicationContext = SpringApplication
|
||||
.run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedDataSourceConfiguration.class,
|
||||
BatchAutoConfiguration.class,
|
||||
TaskBatchAutoConfiguration.class,
|
||||
TaskJobLauncherAutoConfiguration.class }, enabledArgs);
|
||||
}
|
||||
catch (IllegalStateException exception) {
|
||||
isExceptionThrown = true;
|
||||
}
|
||||
assertThat(isExceptionThrown).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskJobLauncherPickOneJob() {
|
||||
String[] enabledArgs = new String[] {
|
||||
"--spring.cloud.task.batch.commandLineRunnerEnabled=true",
|
||||
"--spring.cloud.task.batch.jobNames=jobSucceed" };
|
||||
boolean isExceptionThrown = false;
|
||||
try {
|
||||
this.applicationContext = SpringApplication
|
||||
.run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedDataSourceConfiguration.class,
|
||||
BatchAutoConfiguration.class,
|
||||
TaskBatchAutoConfiguration.class,
|
||||
TaskJobLauncherAutoConfiguration.class }, enabledArgs);
|
||||
}
|
||||
catch (IllegalStateException exception) {
|
||||
isExceptionThrown = true;
|
||||
}
|
||||
assertThat(isExceptionThrown).isFalse();
|
||||
validateContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommandLineRunnerSetToFalse() {
|
||||
String[] enabledArgs = new String[] { };
|
||||
this.applicationContext = SpringApplication
|
||||
.run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedDataSourceConfiguration.class,
|
||||
BatchAutoConfiguration.class,
|
||||
TaskBatchAutoConfiguration.class,
|
||||
TaskJobLauncherAutoConfiguration.class }, enabledArgs);
|
||||
validateContext();
|
||||
assertThat(applicationContext.getBean(JobLauncherCommandLineRunner.class)).isNotNull();
|
||||
boolean exceptionThrown = false;
|
||||
try {
|
||||
applicationContext.getBean(TaskJobLauncherCommandLineRunner.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException exception) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
assertThat(exceptionThrown).isTrue();
|
||||
validateContext();
|
||||
}
|
||||
|
||||
private void validateContext() {
|
||||
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
|
||||
|
||||
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1));
|
||||
|
||||
Set<Long> jobExecutionIds = taskExplorer
|
||||
.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());
|
||||
|
||||
assertThat(jobExecutionIds.size()).isEqualTo(1);
|
||||
assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1);
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
@EnableTask
|
||||
public static class JobConfiguration {
|
||||
|
||||
@Autowired
|
||||
private JobBuilderFactory jobBuilderFactory;
|
||||
|
||||
@Autowired
|
||||
private StepBuilderFactory stepBuilderFactory;
|
||||
|
||||
@Bean
|
||||
public Job job() {
|
||||
return jobBuilderFactory.get("job")
|
||||
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() {
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)
|
||||
throws Exception {
|
||||
System.out.println("Executed");
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
}).build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
@EnableTask
|
||||
public static class JobWithFailureConfiguration {
|
||||
|
||||
@Autowired
|
||||
private JobBuilderFactory jobBuilderFactory;
|
||||
|
||||
@Autowired
|
||||
private StepBuilderFactory stepBuilderFactory;
|
||||
|
||||
@Bean
|
||||
public Job jobFail() {
|
||||
return jobBuilderFactory.get("jobA")
|
||||
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() {
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution,
|
||||
ChunkContext chunkContext)
|
||||
throws Exception {
|
||||
System.out.println("Executed");
|
||||
throw new IllegalStateException("WHOOPS");
|
||||
}
|
||||
}).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job jobFun() {
|
||||
return jobBuilderFactory.get("jobSucceed")
|
||||
.start(stepBuilderFactory.get("step1Succeed").tasklet(new Tasklet() {
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution,
|
||||
ChunkContext chunkContext)
|
||||
throws Exception {
|
||||
System.out.println("Executed");
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
}).build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ import static org.junit.Assert.assertEquals;
|
||||
*/
|
||||
public class TaskBatchExecutionListenerTests {
|
||||
|
||||
public static final String[] ARGS = new String[] {"--spring.cloud.task.closecontext_enable=false"};
|
||||
public static final String[] ARGS = new String[] {};
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user