Refactored dependency management

Created a Spring Boot starter that can be used to configure Spring Cloud
Task and it's related functionality.

Updates per code review

Removed autowiring of app context

Refactored DeployerPartitionHandler to correctly use environment variables

Exposed deployment properties of TaskLauncher

Exposed deployment properties via the TaskLaunchRequest

Updated based on code review
This commit is contained in:
Michael Minella
2016-06-30 23:10:08 -05:00
committed by Glenn Renfro
parent a1c1dd161f
commit 57e9d4dcae
39 changed files with 369 additions and 142 deletions

View File

@@ -70,7 +70,7 @@
<module>spring-cloud-task-docs</module>
<module>spring-cloud-task-batch</module>
<module>spring-cloud-task-stream</module>
<module>spring-cloud-task-integration-tests</module>
<module>spring-cloud-task-starter</module>
</modules>
<properties>
@@ -224,5 +224,11 @@
<module>spring-cloud-task-samples</module>
</modules>
</profile>
<profile>
<id>integration-test</id>
<modules>
<module>spring-cloud-task-integration-tests</module>
</modules>
</profile>
</profiles>
</project>

View File

@@ -29,6 +29,11 @@
<artifactId>spring-cloud-deployer-local</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-support</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-integration</artifactId>
@@ -43,6 +48,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@@ -105,6 +105,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
private Environment environment;
private Map<String, String> deploymentProperties;
public DeployerPartitionHandler(TaskLauncher taskLauncher,
JobExplorer jobExplorer,
Resource resource,
@@ -168,6 +170,15 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
this.timeout = timeout;
}
/**
* Map of deployment properties to be used by the {@link TaskLauncher}
*
* @param deploymentProperties
*/
public void setDeploymentProperties(Map<String, String> deploymentProperties) {
this.deploymentProperties = deploymentProperties;
}
@BeforeTask
public void beforeTask(TaskExecution taskExecution) {
this.taskExecution = taskExecution;
@@ -213,32 +224,38 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
}
private void launchWorker(StepExecution workerStepExecution) {
//TODO: Refactor these to be passed as command line args once SCD-20 is complete
// https://github.com/spring-cloud/spring-cloud-deployer/issues/20
Map<String, String> arguments = getArguments(this.taskExecution.getArguments());
arguments.put(SPRING_CLOUD_TASK_JOB_EXECUTION_ID,
String.valueOf(workerStepExecution.getJobExecution().getId()));
arguments.put(SPRING_CLOUD_TASK_STEP_EXECUTION_ID,
String.valueOf(workerStepExecution.getId()));
arguments.put(SPRING_CLOUD_TASK_STEP_NAME, this.stepName);
List<String> arguments = new ArrayList<>();
arguments.addAll(this.taskExecution.getArguments());
arguments.add(formatArgument(SPRING_CLOUD_TASK_JOB_EXECUTION_ID,
String.valueOf(workerStepExecution.getJobExecution().getId())));
arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_EXECUTION_ID,
String.valueOf(workerStepExecution.getId())));
arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_NAME, this.stepName));
Map<String, String> environmentProperties = new HashMap<>(this.environmentProperties.size());
environmentProperties.putAll(getCurrentEnvironmentProperties());
environmentProperties.putAll(this.environmentProperties);
AppDefinition definition =
new AppDefinition(String.format("%s:%s:%s",
taskExecution.getTaskName(),
workerStepExecution.getJobExecution().getJobInstance().getJobName(),
workerStepExecution.getStepName()),
arguments);
Map<String, String> environmentProperties = new HashMap<>(this.environmentProperties.size());
environmentProperties.putAll(getCurrentEnvironmentProperties());
environmentProperties.putAll(this.environmentProperties);
environmentProperties);
AppDeploymentRequest request =
new AppDeploymentRequest(definition, this.resource, environmentProperties);
new AppDeploymentRequest(definition,
this.resource,
this.deploymentProperties,
arguments);
taskLauncher.launch(request);
}
private String formatArgument(String key, String value) {
return String.format("--%s=%s", key, value);
}
private Collection<StepExecution> pollReplies(final StepExecution masterStepExecution,
final Set<StepExecution> executed,
final Set<StepExecution> candidates,

View File

@@ -147,9 +147,9 @@ public class DeployerPartitionHandlerTests {
AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask:partitionedJob:step1:partition1", appDefinition.getName());
assertEquals("1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID));
assertEquals("4", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID));
assertEquals("step1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1")));
assertEquals(1, results.size());
StepExecution resultStepExecution = results.iterator().next();
@@ -344,16 +344,16 @@ public class DeployerPartitionHandlerTests {
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource());
assertEquals(2, request.getDeploymentProperties().size());
assertEquals("bar", request.getDeploymentProperties().get("foo"));
assertEquals("qux", request.getDeploymentProperties().get("baz"));
assertEquals(2, request.getDefinition().getProperties().size());
assertEquals("bar", request.getDefinition().getProperties().get("foo"));
assertEquals("qux", request.getDefinition().getProperties().get("baz"));
AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask:partitionedJob:step1:partition1", appDefinition.getName());
assertEquals("1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID));
assertEquals("4", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID));
assertEquals("step1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1")));
assertEquals(1, results.size());
StepExecution resultStepExecution = results.iterator().next();
@@ -361,6 +361,10 @@ public class DeployerPartitionHandlerTests {
assertEquals("step1:partition1", resultStepExecution.getStepName());
}
private String formatArgs(String key, String value) {
return String.format("--%s=%s", key, value);
}
@Test
public void testOverridingEnvironmentProperties() throws Exception {
@@ -399,17 +403,17 @@ public class DeployerPartitionHandlerTests {
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource());
assertEquals(3, request.getDeploymentProperties().size());
assertEquals("bar", request.getDeploymentProperties().get("foo"));
assertEquals("qux", request.getDeploymentProperties().get("baz"));
assertEquals("batch", request.getDeploymentProperties().get("task"));
assertEquals(3, request.getDefinition().getProperties().size());
assertEquals("bar", request.getDefinition().getProperties().get("foo"));
assertEquals("qux", request.getDefinition().getProperties().get("baz"));
assertEquals("batch", request.getDefinition().getProperties().get("task"));
AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask:partitionedJob:step1:partition1", appDefinition.getName());
assertEquals("1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID));
assertEquals("4", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID));
assertEquals("step1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1")));
assertEquals(1, results.size());
StepExecution resultStepExecution = results.iterator().next();
@@ -539,6 +543,58 @@ public class DeployerPartitionHandlerTests {
validateStepExecutionResults(results);
}
@Test
public void testDeployerProperties() throws Exception {
StepExecution masterStepExecution = createMasterStepExecution();
JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment);
Map<String, String> deploymentProperties = new HashMap<>(2);
deploymentProperties.put("foo", "bar");
deploymentProperties.put("baz", "qux");
handler.setDeploymentProperties(deploymentProperties);
TaskExecution taskExecution = new TaskExecution();
taskExecution.setTaskName("partitionedJobTask");
Set<StepExecution> stepExecutions = new HashSet<>();
stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish);
handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource());
assertEquals(2, request.getDeploymentProperties().size());
assertEquals("bar", request.getDeploymentProperties().get("foo"));
assertEquals("qux", request.getDeploymentProperties().get("baz"));
AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask:partitionedJob:step1:partition1", appDefinition.getName());
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1")));
assertEquals(1, results.size());
StepExecution resultStepExecution = results.iterator().next();
assertEquals(BatchStatus.COMPLETED, resultStepExecution.getStatus());
assertEquals("step1:partition1", resultStepExecution.getStepName());
}
private StepExecution getStepExecutionFinish(StepExecution stepExecutionStart, BatchStatus status) {
StepExecution workerStepExecutionFinish = new StepExecution(stepExecutionStart.getStepName(), stepExecutionStart.getJobExecution());
workerStepExecutionFinish.setId(stepExecutionStart.getId());
@@ -592,9 +648,9 @@ public class DeployerPartitionHandlerTests {
AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask:partitionedJob:step1:partition" + (i - 3), appDefinition.getName());
assertEquals("1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID));
assertEquals(String.valueOf(i), appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID));
assertEquals("step1", appDefinition.getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, String.valueOf(i))));
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1")));
}
}

View File

@@ -19,6 +19,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-maven</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
@@ -42,10 +51,6 @@
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2016 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.configuration;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.deployer.resource.maven.MavenProperties;
import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader;
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
/**
* Autoconfiguration of a file or Maven based {@link ResourceLoader}.
*
* @author Michael Minella
* @since 1.0.1
*/
@Configuration
public class ResourceLoadingAutoConfiguration {
@Configuration
@ConditionalOnClass(MavenResourceLoader.class)
public static class MavenResourceLoadingAutoConfiguration {
@Bean
public MavenResourceLoader mavenResourceLoader(MavenProperties mavenProperties) {
return new MavenResourceLoader(mavenProperties);
}
@Bean
@ConditionalOnMissingBean
public DelegatingResourceLoader delegatingResourceLoader(MavenResourceLoader mavenResourceLoader) {
Map<String, ResourceLoader> loaders = new HashMap<>(1);
loaders.put("maven", mavenResourceLoader);
return new DelegatingResourceLoader(loaders);
}
@Bean
public MavenProperties mavenProperties() {
return new MavenConfigurationProperties();
}
@ConfigurationProperties(prefix = "maven")
public static class MavenConfigurationProperties extends MavenProperties {}
}
@Configuration
@ConditionalOnMissingClass("org.springframework.cloud.deployer.resource.maven.MavenResourceLoader")
public static class LocalResourceLoadingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DelegatingResourceLoader delegatingResourceLoader(ApplicationContext context) {
Map<String, ResourceLoader> loaders = new HashMap<>(1);
loaders.put("file", context);
return new DelegatingResourceLoader(loaders);
}
}
}

View File

@@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.configuration.ResourceLoadingAutoConfiguration

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>org.springframework.cloud</groupId>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-task-dependencies</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
@@ -17,10 +16,12 @@
<properties>
<spring-cloud-stream.version>1.0.2.RELEASE</spring-cloud-stream.version>
<spring-cloud-deployer-spi.version>1.0.0.RELEASE</spring-cloud-deployer-spi.version>
<spring-cloud-deployer-local.version>1.0.0.RELEASE</spring-cloud-deployer-local.version>
<spring-cloud-deployer-spi.version>1.0.1.RELEASE</spring-cloud-deployer-spi.version>
<spring-cloud-deployer-local.version>1.0.1.RELEASE</spring-cloud-deployer-local.version>
<spring-cloud-stream-binder-rabbit.version>1.0.2.RELEASE</spring-cloud-stream-binder-rabbit.version>
<spring.cloud.deployer.resource.support>1.0.0.RELEASE</spring.cloud.deployer.resource.support>
<spring-cloud-deployer-resource-support.version>1.0.1.RELEASE</spring-cloud-deployer-resource-support.version>
<spring-cloud-deployer-resource-maven.version>1.0.1.RELEASE</spring-cloud-deployer-resource-maven.version>
<spring-batch.version>3.0.7.RELEASE</spring-batch.version>
</properties>
<dependencyManagement>
<dependencies>
@@ -65,15 +66,10 @@
<version>${spring-cloud-deployer-local.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-local</artifactId>
<version>${spring-cloud-deployer-spi.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-support</artifactId>
<version>${spring.cloud.deployer.resource.support}</version>
<version>${spring-cloud-deployer-resource-support.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
@@ -81,6 +77,16 @@
<version>${spring-cloud-stream-binder-rabbit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-maven</artifactId>
<version>${spring-cloud-deployer-resource-maven.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<version>${spring-batch.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -64,11 +64,16 @@ look like the following:
@Bean
public PartitionHandler partitionHandler(TaskLauncher taskLauncher,
JobExplorer jobExplorer) throws Exception {
MavenResource resource =
MavenProperties mavenProperties = new MavenProperties();
mavenProperties.setRemoteRepositories(new HashMap<>(Collections.singletonMap("springRepo",
new MavenProperties.RemoteRepository(repository))));
MavenResource resource =
MavenResource.parse(String.format("%s:%s:%s",
"io.spring.cloud",
"partitioned-batch-job",
"1.0.0.RELEASE"));
"1.0.0.RELEASE"), mavenProperties);
DeployerPartitionHandler partitionHandler =
new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, "workerStep");
@@ -85,11 +90,12 @@ public PartitionHandler partitionHandler(TaskLauncher taskLauncher,
The `Resource` to be executed is expected to be a Spring Boot über-jar with a
`DeployerStepExecutionHandler` configured as a `CommandLineRunner` in the current context.
Both the master and slave are expected to have visibility into the same data store being
used as the job repository and task repository. Once the underlying infrastructure has
bootstrapped the Spring Boot jar and Spring Boot has launched the
`DeployerStepExecutionHandler`, the step handler will execute the Step requested. An
example of configuring the `DefaultStepExecutionHandler`:
The repository enumerated in the example above should be the location of the remote repository
from which the über-jar is located. Both the master and slave are expected to have
visibility into the same data store being used as the job repository and task repository.
Once the underlying infrastructure has bootstrapped the Spring Boot jar and Spring Boot
has launched the `DeployerStepExecutionHandler`, the step handler will execute the Step
requested. An example of configuring the `DefaultStepExecutionHandler` is show below:
```
@Bean

View File

@@ -42,6 +42,10 @@ repository execute a maven build from the `spring-cloud-task-samples` directory
property `skipInstall` set to false. For example:
`mvn clean install`.
NOTE: The maven.remoteRepositories.springRepo.url property will need to be set to
the location of the remote repository from which the über-jar is located. If not
set, then there will be no remote repository, so it will rely upon the local repository only.
[[stream-integration-launching-sink-dataflow]]
=== Spring Cloud Data Flow

View File

@@ -36,5 +36,14 @@
<artifactId>spring-cloud-task-batch</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-support</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -27,7 +27,7 @@ $ ./mvnw clean install
[source,shell,indent=2]
----
$ java -jar target/batch-events-1.0.0.BUILD-SNAPSHOT.jar --spring.cloud.stream.bindings.batch-events.contentType=application/json
$ java -jar target/batch-events-1.0.1.BUILD-SNAPSHOT.jar --spring.cloud.stream.bindings.batch-events.contentType=application/json
----
For example you can listen for specific job execution events on a specified channel with a Spring Cloud Stream Sink
@@ -35,7 +35,7 @@ like the log sink using the following:
[source,shell,indent=2]
----
$ java -jar <PATH_TO_LOG_SINK_JAR>/log-sink-rabbit-1.0.0.BUILD-SNAPSHOT.jar --server.port=9090
$ java -jar <PATH_TO_LOG_SINK_JAR>/log-sink-rabbit-1.0.1.BUILD-SNAPSHOT.jar --server.port=9090
--spring.cloud.stream.bindings.input.destination=job-execution-events
----

View File

@@ -34,14 +34,6 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
@@ -65,6 +57,11 @@
<artifactId>spring-cloud-stream-test-support-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
</dependencies>
<build>

View File

@@ -22,5 +22,5 @@ $ mvn clean package
[source,shell,indent=2]
----
$ java -jar target/batch-job-1.0.0.BUILD-SNAPSHOT.jar
$ java -jar target/batch-job-1.0.1.BUILD-SNAPSHOT.jar
----

View File

@@ -40,11 +40,8 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-batch</artifactId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>

View File

@@ -22,7 +22,7 @@ $ export spring_datasource_url=jdbc:mysql://localhost:3306/<your database>
$ export spring_datasource_username=<your username>
$ export spring_datasource_password=<your password>
$ export spring_datasource_driverClassName=org.mariadb.jdbc.Driver
$ java -jar -Dspring.profiles.active=master target/partitioned-batch-job-1.0.0.BUILD-SNAPSHOT.jar
$ java -jar -Dspring.profiles.active=master target/partitioned-batch-job-1.0.1.BUILD-SNAPSHOT.jar
----
NOTE: This example will use require a MySql RDBMS repository and currently uses the mariadb jdbc driver to connect.

View File

@@ -40,7 +40,8 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-batch</artifactId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
@@ -62,7 +63,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -38,6 +38,7 @@ import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.deployer.resource.maven.MavenResource;
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
import org.springframework.cloud.deployer.spi.local.LocalDeployerProperties;
import org.springframework.cloud.deployer.spi.local.LocalTaskLauncher;
import org.springframework.cloud.deployer.spi.task.TaskLauncher;
@@ -47,6 +48,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.Resource;
/**
* @author Michael Minella
@@ -69,6 +71,9 @@ public class JobConfiguration {
@Autowired
private ConfigurableApplicationContext context;
@Autowired
private DelegatingResourceLoader delegatingResourceLoader;
private static final int GRID_SIZE = 4;
@Bean
@@ -91,7 +96,7 @@ public class JobConfiguration {
@Bean
public PartitionHandler partitionHandler(TaskLauncher taskLauncher, JobExplorer jobExplorer) throws Exception {
MavenResource resource = MavenResource.parse("io.spring.cloud:partitioned-batch-job:1.0.0.BUILD-SNAPSHOT");
Resource resource = delegatingResourceLoader.getResource("maven://io.spring.cloud:partitioned-batch-job:1.0.1.BUILD-SNAPSHOT");
DeployerPartitionHandler partitionHandler = new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, "workerStep");

View File

@@ -1,2 +1,3 @@
spring.application.name=Partitioned Batch Job Task
logging.level.org.springframework.cloud.task=DEBUG
maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot

View File

@@ -17,7 +17,7 @@ $ ./mvnw clean install
[source,shell,indent=2]
----
$ java -jar target/task-events-1.0.0.BUILD-SNAPSHOT.jar --spring.cloud.stream.bindings.task-events.contentType=application/json
$ java -jar target/task-events-1.0.1.BUILD-SNAPSHOT.jar --spring.cloud.stream.bindings.task-events.contentType=application/json
----
You can listen for the events on the task-events channel with a Spring Cloud Stream Sink
@@ -25,7 +25,7 @@ like the log sink using the following:
[source,shell,indent=2]
----
$ java -jar <PATH_TO_LOG_SINK_JAR>/log-sink-rabbit-1.0.0.BUILD-SNAPSHOT.jar --server.port=9090 --spring.cloud.stream.bindings.input.destination=task-events
$ java -jar <PATH_TO_LOG_SINK_JAR>/log-sink-rabbit-1.0.1.BUILD-SNAPSHOT.jar --server.port=9090 --spring.cloud.stream.bindings.input.destination=task-events
----
== Dependencies:

View File

@@ -41,12 +41,8 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-stream</artifactId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>

View File

@@ -40,7 +40,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-stream</artifactId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>

View File

@@ -58,7 +58,7 @@ public class TaskProcessor {
}
properties.put("payload", message);
TaskLaunchRequest request = new TaskLaunchRequest(processorProperties.getUri(), null, properties);
TaskLaunchRequest request = new TaskLaunchRequest(processorProperties.getUri(), null, properties, null);
return new GenericMessage<TaskLaunchRequest>(request);
}

View File

@@ -16,15 +16,12 @@
package io.spring;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.springframework.cloud.stream.test.matcher.MessageQueueMatcher.receivesPayloadThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.stream.annotation.Bindings;
@@ -34,6 +31,10 @@ import org.springframework.cloud.task.launcher.TaskLaunchRequest;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.springframework.cloud.stream.test.matcher.MessageQueueMatcher.receivesPayloadThat;
/**
* @author Glenn Renfro
*/
@@ -56,7 +57,7 @@ public class TaskProcessorApplicationTests {
Map<String, String> properties = new HashMap();
properties.put("payload", DEFAULT_PAYLOAD);
TaskLaunchRequest expectedRequest = new TaskLaunchRequest("maven://org.springframework.cloud.task.app:"
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT", null, properties);
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT", null, properties, null);
assertThat(collector.forChannel(channels.output()), receivesPayloadThat(is(expectedRequest)));
}

View File

@@ -44,7 +44,8 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-stream</artifactId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>

View File

@@ -0,0 +1 @@
maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot

View File

@@ -16,15 +16,13 @@
package io.spring;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.HashMap;
import java.util.Map;
import io.spring.configuration.TaskSinkConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.cloud.deployer.spi.task.LaunchState;
@@ -36,6 +34,9 @@ import org.springframework.context.ApplicationContext;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author Glenn Renfro
*/
@@ -60,7 +61,7 @@ public class TaskSinkApplicationTests {
Map<String, String> properties = new HashMap();
properties.put("server.port", "0");
TaskLaunchRequest request = new TaskLaunchRequest("maven://org.springframework.cloud.task.app:"
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT", null, properties);
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT", null, properties, null);
GenericMessage<TaskLaunchRequest> message = new GenericMessage<TaskLaunchRequest>(request);
this.sink.input().send(message);
assertEquals(LaunchState.complete, testTaskLauncher.status("TESTSTATUS").getState());

View File

@@ -0,0 +1 @@
maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot

View File

@@ -22,5 +22,5 @@ $ mvn clean package
[source,shell,indent=2]
----
$ java -jar target/timestamp-task-1.0.0.BUILD-SNAPSHOT.jar
$ java -jar target/timestamp-task-1.0.1.BUILD-SNAPSHOT.jar
----

View File

@@ -45,7 +45,8 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-core</artifactId>
<artifactId>spring-cloud-task-starter</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-parent</artifactId>
<version>1.0.1.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-task-starter</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Task Starter</name>
<description>Spring Boot starter for Spring Cloud Task</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-stream</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -16,6 +16,7 @@
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
@@ -26,6 +27,7 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
@@ -70,6 +72,7 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-resource-support</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -25,6 +25,7 @@ import org.springframework.batch.core.SkipListener;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.stream.annotation.EnableBinding;
@@ -54,6 +55,7 @@ import org.springframework.messaging.MessageChannel;
* @author Glenn Renfro
*/
@Configuration
@ConditionalOnClass(Job.class)
@ConditionalOnBean(value = { Job.class, TaskLifecycleListener.class })
@ConditionalOnProperty(prefix = "spring.cloud.task.batch.events", name = "enabled", havingValue = "true", matchIfMissing = true)
public class BatchEventAutoConfiguration {
@@ -68,11 +70,12 @@ public class BatchEventAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TaskBatchEventListenerBeanPostProcessor batchTaskExecutionListenerBeanPostProcessor() {
public TaskBatchEventListenerBeanPostProcessor batchTaskEventListenerBeanPostProcessor() {
return new TaskBatchEventListenerBeanPostProcessor();
}
@Configuration
@ConditionalOnClass(EnableBinding.class)
@EnableBinding(BatchEventsChannels.class)
@ConditionalOnMissingBean(name = JOB_EXECUTION_EVENTS_LISTENER)
public static class JobExecutionListenerConfiguration {

View File

@@ -32,7 +32,6 @@ import org.springframework.batch.core.step.item.SimpleChunkProvider;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.core.step.tasklet.TaskletStep;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.task.batch.listener.BatchEventAutoConfiguration;

View File

@@ -37,21 +37,25 @@ public class TaskLaunchRequest implements Serializable{
private static final long serialVersionUID = 1L;
private String uri;
private List<String> commandlineArguments;
private Map<String, String> properties;
private Map<String, String> environmentProperties;
private Map<String, String> deploymentProperties;
/**
* Constructor for the TaskLaunchRequest;
* @param uri the URI to the task artifact to be launched.
* @param commandlineArguments list of commandlineArguments to be used by the task
* @param properties is the environment variables for this task.
* @param environmentProperties are the environment variables for this task.
* @param deploymentProperties are the variables used to setup task on the platform.
*/
public TaskLaunchRequest(String uri, List<String> commandlineArguments,
Map<String, String> properties) {
Map<String, String> environmentProperties,
Map<String, String> deploymentProperties) {
Assert.hasText(uri, "uri must not be empty nor null.");
this.uri = uri;
this.commandlineArguments = (commandlineArguments == null) ? new ArrayList<String>() : commandlineArguments;
this.properties = properties == null ? new HashMap() : properties;
this.environmentProperties = environmentProperties == null ? new HashMap<String, String>() : environmentProperties;
this.deploymentProperties = deploymentProperties == null ? new HashMap<String, String>() : deploymentProperties;
}
/**
@@ -73,8 +77,17 @@ public class TaskLaunchRequest implements Serializable{
* @return map containing the environment variables for the task.
*/
public Map<String, String> getProperties() {
return properties;
public Map<String, String> getEnvironmentProperties() {
return environmentProperties;
}
/**
* Returns the properties used by a {@link org.springframework.cloud.deployer.spi.task.TaskLauncher}
*
* @return deployment properties
*/
public Map<String, String> getDeploymentProperties() {
return deploymentProperties;
}
@Override
@@ -82,7 +95,8 @@ public class TaskLaunchRequest implements Serializable{
return "TaskLaunchRequest{" +
"uri='" + uri + '\'' +
", commandlineArguments=" + commandlineArguments +
", properties=" + properties +
", environmentProperties=" + environmentProperties +
", deploymentProperties=" + deploymentProperties +
'}';
}
@@ -103,7 +117,11 @@ public class TaskLaunchRequest implements Serializable{
if (!(commandlineArguments != null ? commandlineArguments.equals(that.commandlineArguments) : that.commandlineArguments == null)){
return false;
}
return properties != null ? properties.equals(that.properties) : that.properties == null;
if(!(deploymentProperties != null ? deploymentProperties.equals(that.deploymentProperties) : that.deploymentProperties == null))
{
return false;
}
return environmentProperties != null ? environmentProperties.equals(that.environmentProperties) : that.environmentProperties == null;
}
@@ -111,7 +129,8 @@ public class TaskLaunchRequest implements Serializable{
public int hashCode() {
int result = uri != null ? uri.hashCode() : 0;
result = 31 * result + (commandlineArguments != null ? commandlineArguments.hashCode() : 0);
result = 31 * result + (properties != null ? properties.hashCode() : 0);
result = 31 * result + (environmentProperties != null ? environmentProperties.hashCode() : 0);
result = 31 * result + (deploymentProperties != null ? deploymentProperties.hashCode() : 0);
return result;
}
}

View File

@@ -16,21 +16,13 @@
package org.springframework.cloud.task.launcher;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.deployer.resource.maven.MavenProperties;
import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader;
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
import org.springframework.cloud.deployer.spi.local.LocalDeployerProperties;
import org.springframework.cloud.deployer.spi.local.LocalTaskLauncher;
import org.springframework.cloud.deployer.spi.task.TaskLauncher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
/**
* Creates the appropriate Task Launcher Configuration based on the TaskLauncher
@@ -51,26 +43,4 @@ public class TaskLauncherConfiguration {
return new LocalTaskLauncher(new LocalDeployerProperties());
}
}
@Bean
public MavenResourceLoader mavenResourceLoader(MavenProperties properties) {
return new MavenResourceLoader(properties);
}
@Bean
@ConditionalOnMissingBean(DelegatingResourceLoader.class)
public DelegatingResourceLoader delegatingResourceLoader(MavenResourceLoader mavenResourceLoader) {
Map<String, ResourceLoader> loaders = new HashMap<>();
loaders.put("maven", mavenResourceLoader);
return new DelegatingResourceLoader(loaders);
}
@Bean
public MavenProperties mavenProperties() {
return new MavenConfigurationProperties();
}
@ConfigurationProperties(prefix = "maven")
static class MavenConfigurationProperties extends MavenProperties {
}
}

View File

@@ -61,8 +61,8 @@ public class TaskLauncherSink {
Assert.notNull(taskLauncher, "TaskLauncher has not been initialized");
logger.info("Launching Task for the following resource " + taskLaunchRequest);
Resource resource = delegatingResourceLoader.getResource(taskLaunchRequest.getUri());
AppDefinition definition = new AppDefinition("Task-" + taskLaunchRequest.hashCode(), taskLaunchRequest.getProperties());
AppDeploymentRequest request = new AppDeploymentRequest(definition, resource, null, taskLaunchRequest.getCommandlineArguments());
AppDefinition definition = new AppDefinition("Task-" + taskLaunchRequest.hashCode(), taskLaunchRequest.getEnvironmentProperties());
AppDeploymentRequest request = new AppDeploymentRequest(definition, resource, taskLaunchRequest.getDeploymentProperties(), taskLaunchRequest.getCommandlineArguments());
taskLauncher.launch(request);
}

View File

@@ -102,7 +102,7 @@ public class TaskLauncherSinkTests {
public void testNoTaskLauncher() {
TaskLauncherSink sink = new TaskLauncherSink();
sink.taskLauncherSink(new TaskLaunchRequest("maven://org.springframework.cloud.task.app:"
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT",null, properties));
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT",null, properties, null));
}
private TaskConfiguration.TestTaskLauncher launchTask(List<String> commandLineArgs) {
@@ -110,7 +110,7 @@ public class TaskLauncherSinkTests {
context.getBean(TaskConfiguration.TestTaskLauncher.class);
TaskLaunchRequest request = new TaskLaunchRequest("maven://org.springframework.cloud.task.app:"
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT",commandLineArgs, properties);
+ "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT",commandLineArgs, properties, null);
GenericMessage<TaskLaunchRequest> message = new GenericMessage<>(request);
this.sink.input().send(message);
return testTaskLauncher;

View File

@@ -0,0 +1 @@
maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot