Full editing pass

I corrected spelling and grammar and gave it a voice (flat, corporate) consistent with our other docs. I added a couple TODOs where I thought another sample would help.

Incorporated Glenn Renfro's comments

Glenn gave my work a thorough review (thanks, Glenn!). This commit incorporates his changes.

One more change

I missed one of Glenn's fixes (by forgetting to save one last time before the previous commit). I have corrected that oversight
This commit is contained in:
Jay Bryant
2018-03-06 09:07:51 -06:00
committed by Glenn Renfro
parent f3e4b96ffc
commit 5cd934eb97
8 changed files with 539 additions and 516 deletions

View File

@@ -1,6 +1,6 @@
[[appendix-building-the-documentation]]
== Building this documentation
== Building This Documentation
This project uses Maven to generate this documentation. To generate it for yourself,
execute the command: `$ ./mvnw clean package -P full`.
This project uses Maven to generate this documentation. To generate it for yourself,
run the following command: `$ ./mvnw clean package -P full`.

View File

@@ -1,6 +1,5 @@
[[appendix-task-repository-schema]]
== Task repository schema
== Task Repository Schema
[[partintro]]
--
@@ -8,4 +7,3 @@ This appendix provides an ERD for the database schema used in the task repositor
--
image::task_schema.png[]

View File

@@ -4,37 +4,40 @@
[[partintro]]
--
This section goes into more detail about Spring Cloud Task's integrations with Spring
Batch. Tracking the association between a job execution and the task it was executed
within as well as remote partitioning via Spring Cloud Deployer are all covered within
This section goes into more detail about Spring Cloud Task's integration with Spring
Batch. Tracking the association between a job execution and the task in which it was
executed as well as remote partitioning through Spring Cloud Deployer are covered in
this section.
--
[[batch-association]]
== Associating A Job Execution To The Task In Which It Was Executed
== Associating a Job Execution to the Task in which It Was Executed
Spring Boot provides facilities for the execution of batch jobs easily within an über-jar.
Spring Boot's support of this functionality allows for a developer to execute multiple
batch jobs within that execution. Spring Cloud Task provides the ability to associate the
execution of a job (a job execution) with a task's execution so that one can be traced
back to the other.
Spring Boot provides facilities for the execution of batch jobs within an über-jar.
Spring Boot's support of this functionality lets a developer execute multiple batch jobs
within that execution. Spring Cloud Task provides the ability to associate the execution
of a job (a job execution) with a task's execution so that one can be traced back to the
other.
This functionality is accomplished by using the `TaskBatchExecutionListener`. By default,
this listener is auto configured in any context that has both a Spring Batch Job configured
(via having a bean of type `Job` defined in the context) and the spring-cloud-task-batch jar
is available within the classpath. The listener will be injected into all jobs.
Spring Cloud Task achieves this functionality by using the `TaskBatchExecutionListener`.
By default,
this listener is auto configured in any context that has both a Spring Batch Job
configured (by having a bean of type `Job` defined in the context) and the
`spring-cloud-task-batch` jar on the classpath. The listener is injected into all jobs
that meet those conditions.
[[batch-association-override]]
=== Overriding the TaskBatchExecutionListener
To prevent the listener from being injected into any batch jobs within the current context,
the autoconfiguration can be disabled via standard Spring Boot mechanisms.
To prevent the listener from being injected into any batch jobs within the current
context, you can disable the autoconfiguration by using standard Spring Boot mechanisms.
To only have the listener injected into particular jobs within the context, the
`batchTaskExecutionListenerBeanPostProcessor` may be overridden and a list of job bean ids
can be provided:
To only have the listener injected into particular jobs within the context, override the
`batchTaskExecutionListenerBeanPostProcessor` and provide a list of job bean IDs, as shown
in the following example:
```
[source,java]
----
public TaskBatchExecutionListenerBeanPostProcessor batchTaskExecutionListenerBeanPostProcessor() {
TaskBatchExecutionListenerBeanPostProcessor postProcessor =
new TaskBatchExecutionListenerBeanPostProcessor();
@@ -43,29 +46,31 @@ public TaskBatchExecutionListenerBeanPostProcessor batchTaskExecutionListenerBea
return postProcessor;
}
```
NOTE: A sample batch application can be found in the samples module
of the Spring Cloud Task Project
----
NOTE: You can find a sample batch application in the samples module of the Spring Cloud
Task Project,
https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/batch-job[here].
[[batch-partitioning]]
== Remote Partitioning
Spring Cloud Deployer provides facilities for launching Spring Boot based applications on
most cloud infrastructures. The `DeployerPartitionHandler` and
Spring Cloud Deployer provides facilities for launching Spring Boot-based applications on
most cloud infrastructures. The `DeployerPartitionHandler` and
`DeployerStepExecutionHandler` delegate the launching of worker step executions to Spring
Cloud Deployer.
To configure the `DeployerStepExecutionHandler`, a `Resource` representing the Spring Boot
über-jar to be executed, a `TaskLauncher`, and a `JobExplorer` are all required. You can
configure any environment properties as well as the max number of workers to be executing
at once, the interval to poll for the results (defaults to 10 seconds), and a timeout
(defaults to -1 or no timeout). An example of configuring this `PartitionHandler` would
look like the following:
To configure the `DeployerStepExecutionHandler`, you must provide a `Resource`
representing the Spring Boot über-jar to be executed, a `TaskLauncher`, and a
`JobExplorer`. You can configure any environment properties as well as the max number of
workers to be executing at once, the interval to poll for the results (defaults to 10
seconds), and a timeout (defaults to -1 or no timeout). The following example shows how
configuring this `PartitionHandler` might look:
```
[source,java]
----
@Bean
public PartitionHandler partitionHandler(TaskLauncher taskLauncher,
JobExplorer jobExplorer) throws Exception {
@@ -88,28 +93,31 @@ public PartitionHandler partitionHandler(TaskLauncher taskLauncher,
commandLineArgs.add("--spring.cloud.task.initialize.enable=false");
commandLineArgs.add("--spring.batch.initializer.enabled=false");
partitionHandler.setCommandLineArgsProvider(new PassThroughCommandLineArgsProvider(commandLineArgs));
partitionHandler.setCommandLineArgsProvider(
new PassThroughCommandLineArgsProvider(commandLineArgs));
partitionHandler.setEnvironmentVariablesProvider(new NoOpEnvironmentVariablesProvider());
partitionHandler.setMaxWorkers(2);
partitionHandler.setApplicationName("PartitionedBatchJobTask");
return partitionHandler;
}
```
----
NOTE: When passing environment variables to partitions, each partition may
be on a different machine with a different environment settings.
So only pass those that are required.
be on a different machine with different environment settings.
Consequently, you should pass only those environment variables that are required.
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.
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:
The repository enumerated in the preceding example should be the remote repository in
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 executes the requested
`Step`. The following example shows how to configure the `DefaultStepExecutionHandler`:
```
[source,java]
----
@Bean
public DeployerStepExecutionHandler stepExecutionHandler(JobExplorer jobExplorer) {
DeployerStepExecutionHandler handler =
@@ -117,24 +125,30 @@ public DeployerStepExecutionHandler stepExecutionHandler(JobExplorer jobExplorer
return handler;
}
```
NOTE: A sample remote partition application can be found in the samples module
of the Spring Cloud Task Project
----
NOTE: You can find a sample remote partition application in the samples module of the
Spring Cloud Task project,
https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/partitioned-batch-job[here].
=== Notes on developing a batch partitioned app for the Yarn platform
=== Notes on Developing a Batch-partitioned Application for the Yarn Platform
* When deploying partitioned apps on the Yarn platform be sure to use the
* When deploying partitioned applications on the Yarn platform, you must use the
following dependency for the Spring Cloud Yarn Deployer
(with a version 1.0.2 or higher):
```
+
[source,xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-deployer-yarn</artifactId>
</dependency>
```
* Add the following dependency to the dependency management for a transient dependency required by Yarn:
```
----
* For a transient dependency required by Yarn, add the following dependency to the
dependency management:
+
[source,xml]
----
<dependencyManagement>
<dependencies>
...
@@ -146,45 +160,53 @@ following dependency for the Spring Cloud Yarn Deployer
</dependencies>
...
</dependencyManagement>
```
* Also add the following property to your application.properties: `spring.yarn.container.keepContextAlive=false`.
* When setting up environment variables for the partitions in the PartitionHandler it is recommended that you do not
copy the current working environment properties.
----
* You should also add the following property to your application.properties:
`spring.yarn.container.keepContextAlive=false`.
* When setting up environment variables for the partitions in the PartitionHandler, we
recommend that you do not copy the current working environment properties.
=== Notes on developing a batch partitioned app for the Kubernetes platform
* When deploying partitioned apps on the Kubernetes platform be sure to use the
following dependency for the Spring Cloud Kubernetes Deployer:
```
=== Notes on Developing a Batch-partitioned application for the Kubernetes Platform
* When deploying partitioned apps on the Kubernetes platform, you must use the following
dependency for the Spring Cloud Kubernetes Deployer:
+
[source,xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-deployer-kubernetes</artifactId>
</dependency>
```
----
* The application name for the task application and its partitions need to follow
the following regex pattern: `[a-z0-9]([-a-z0-9]*[a-z0-9])`.
Otherwise, an exception is thrown.
* Application name for the task application and its partitions need to follow
the following regex pattern `[a-z0-9]([-a-z0-9]*[a-z0-9])`.
Else an exception will be thrown.
=== Notes on Developing a Batch-partitioned Application for the Mesos Platform
=== Notes on developing a batch partitioned app for the Mesos platform
* When deploying partitioned apps on the Mesos platform be sure to use the
following dependency for the Spring Cloud Mesos Deployer:
```
* When deploying partitioned apps on the Mesos platform, you must use the following
dependency for the Spring Cloud Mesos Deployer:
+
[source,xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-mesos</artifactId>
</dependency>
```
----
* When configuring the partition handler, do not add any command line arguments to
the `CommandLineArgsProvider`. This is due to Chronos adding the command line
args to the Mesos ID. Thus when launching the partition on Mesos this can cause
the partition to fail to start if command line arg contains characters such as
`/` or `:`.
* When configuring the partition handler, do not add any command line arguments to the
`CommandLineArgsProvider`. You need to avoid adding arguments, because Chronos adds the
command line args to the Mesos ID. If the command line arguments contains characters such
as `/` or `:` when launching the partition on Mesos, the partition fails to start .
=== Notes on developing a batch partitioned app for the Cloud Foundry platform
* When deploying partitioned apps on the Cloud Foundry platform be sure to use
the following dependencies for the Spring Cloud Cloud Foundry Deployer:
```
=== Notes on Developing a Batch-partitioned Application for the Cloud Foundry Platform
* When deploying partitioned apps on the Cloud Foundry platform, you must use the
following dependencies for the Spring Cloud Foundry Deployer:
+
[source,xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-cloudfoundry</artifactId>
@@ -199,25 +221,25 @@ the following dependencies for the Spring Cloud Cloud Foundry Deployer:
<artifactId>reactor-netty</artifactId>
<version>0.5.1.RELEASE</version>
</dependency>
```
----
* When configuring the partition handler, Cloud Foundry Deployment
environment variables need to be established so that the partition handler
can start the partitions. The following list shows the required environment
variables:
- spring_cloud_deployer_cloudfoundry_url
- spring_cloud_deployer_cloudfoundry_org
- spring_cloud_deployer_cloudfoundry_space
- spring_cloud_deployer_cloudfoundry_domain
- spring_cloud_deployer_cloudfoundry_username
- spring_cloud_deployer_cloudfoundry_password
- spring_cloud_deployer_cloudfoundry_services
- spring_cloud_deployer_cloudfoundry_taskTimeout
- `spring_cloud_deployer_cloudfoundry_url`
- `spring_cloud_deployer_cloudfoundry_org`
- `spring_cloud_deployer_cloudfoundry_space`
- `spring_cloud_deployer_cloudfoundry_domain`
- `spring_cloud_deployer_cloudfoundry_username`
- `spring_cloud_deployer_cloudfoundry_password`
- `spring_cloud_deployer_cloudfoundry_services`
- `spring_cloud_deployer_cloudfoundry_taskTimeout`
An example set of deployment environment variables for a partitioned task that
uses a `mysql` database service would look something like this:
uses a `mysql` database service might resemble the following:
```
[source,bash]
----
spring_cloud_deployer_cloudfoundry_url=https://api.local.pcfdev.io
spring_cloud_deployer_cloudfoundry_org=pcfdev-org
spring_cloud_deployer_cloudfoundry_space=pcfdev-space
@@ -226,37 +248,38 @@ spring_cloud_deployer_cloudfoundry_username=admin
spring_cloud_deployer_cloudfoundry_password=admin
spring_cloud_deployer_cloudfoundry_services=mysql
spring_cloud_deployer_cloudfoundry_taskTimeout=300
```
----
NOTE: When using PCF-Dev the following environment variable is also required:
NOTE: When using PCF-Dev, the following environment variable is also required:
`spring_cloud_deployer_cloudfoundry_skipSslValidation=true`
[[batch-informational-messages]]
== Batch Informational Messages
Spring Cloud Task provides the ability for batch jobs to emit informational messages. This
is covered in detail in the section
<<stream.adoc#stream-integration-batch-events, Spring Batch Events>>.
Spring Cloud Task provides the ability for batch jobs to emit informational messages. The
"`<<stream.adoc#stream-integration-batch-events>>`" section covers this feature in detail.
[[batch-failures-and-tasks]]
== Batch Job Exit Codes
As discussed before Spring Cloud Task applications support the ability to record the exit code of a task execution.
However in cases where a user is running a Spring Batch Job within a task, regardless of how the Batch Job
Execution completes the result of the task will always be zero when using default Batch/Boot behavior.
Keep in mind that a task is a boot application and the exit code returned from
the task is the same as a boot application.
To override this behavior and allow the task to return an exit code other than zero
(either 1 `the default` or based on the
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-exit[ExitCodeGenerator]
specified) upon a batch job returning an
As discussed <<features.adoc#features-lifecycle-exit-codes,earlier>>, Spring Cloud Task
applications support the ability to record the exit code of a task execution. However, in
cases where you run a Spring Batch Job within a task, regardless of how the Batch Job
Execution completes, the result of the task is always zero when using the default
Batch/Boot behavior. Keep in mind that a task is a boot application and that the exit code
returned from the task is the same as a boot application.
To override this behavior and allow the task to return an exit code other than zero when a
batch job returns an
https://docs.spring.io/spring-batch/4.0.x/reference/html/step.html#conditionalFlow[ExitStatus]
of "FAILED", set `spring.cloud.task.batch.failOnJobFailure` to true.
This functionality does utilize a new `CommandLineRunner` that replaces the one provided
by Spring Boot. By default it is configured with the same order. However, if you'd like
to customize what order the `CommandLineRunner` is executed in, you can set it's order via
the `spring.cloud.task.batch.commandLineRunnerOrder` property.
To have your task return the exit code based on the result of the batch job
execution, you will need to write your own `CommandLineRunner`.
of `FAILED`, set `spring.cloud.task.batch.failOnJobFailure` to `true`. Then the exit code
can be 1 (the default) or be based on the
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-exit[specified
`ExitCodeGenerator`])
This functionality uses a new `CommandLineRunner` that replaces the one provided by Spring
Boot. By default, it is configured with the same order. However, if you want to customize
the order in which the `CommandLineRunner` is run, you can set its order by setting the
`spring.cloud.task.batch.commandLineRunnerOrder` property. To have your task return the
exit code based on the result of the batch job execution, you need to write your own
`CommandLineRunner`.
//TODO Great place for a example showing how a custom CommandLineRunner

View File

@@ -4,51 +4,55 @@
[[partintro]]
--
This section goes into more detail about Spring Cloud Task. How to use it, how to
configure it, as well as the appropriate extension points are all covered in this section.
This section goes into more detail about Spring Cloud Task, including how to use it, how
to configure it, and the appropriate extension points.
--
[[features-lifecycle]]
== The lifecycle of a Spring Cloud Task
In most cases, the modern cloud environment is designed around the execution of processes
that are not expected to end. If they do, they are typically restarted. While most
platforms do have some method to execute a process that isn't restarted when it ends, the
results of that execution are typically not maintained in a consumable way. Spring Cloud
Task brings the ability to execute short lived processes in an environment and record the
results. This allows for a microservices architecture around short lived processes as
well as longer running services via the integration of tasks by messages.
that are not expected to end. If they do end, they are typically restarted. While most
platforms do have some way to run a process that is not restarted when it ends, the
results of that run are typically not maintained in a consumable way. Spring Cloud
Task offers the ability to execute short-lived processes in an environment and record the
results. Doing so allows for a microservices architecture around short-lived processes as
well as longer running services through the integration of tasks by messages.
While this functionality is useful in a cloud environment, the same issues can arise in a
traditional deployment model as well. When executing Spring Boot applications via a
scheduler like cron, it can be useful to be able to monitor the results of the application
after it's completion.
traditional deployment model as well. When running Spring Boot applications with a
scheduler such as cron, it can be useful to be able to monitor the results of the
application after its completion.
A Spring Cloud Task takes the approach that a Spring Boot application can have a start and an
end and still be successful. Batch applications are just one example of where short lived
processes can be helpful. Spring Cloud Task records lifecycle events of a given task.
Spring Cloud Task takes the approach that a Spring Boot application can have a start and
an end and still be successful. Batch applications are one example of how processes that
are expected to end (and that are often short-lived) can be helpful.
The lifecycle consists of a single task execution. This is a physical execution of a
Spring Boot application configured to be a task (annotated with the `@EnableTask`
Spring Cloud Task records the lifecycle events of a given task. Most long-running
processes, typified by most web applications, do not save their lifecycle events. The
tasks at the heart of Spring Cloud Task do.
The lifecycle consists of a single task execution. This is a physical execution of a
Spring Boot application configured to be a task (that is, it has the `@EnableTask`
annotation).
At the beginning of a task before any `CommandLineRunner` or `ApplicationRunner`
implementations have been executed, an entry in the `TaskRepository` is created recording
the start event. This event is triggered via `SmartLifecycle#start` being triggered by
Spring Framework. This indicates to the system that all beans are ready for use and is
before the execution of any of the `CommandLineRunner` or `ApplicationRunner`
implementations provided by Spring Boot.
At the beginning of a task, before any `CommandLineRunner` or `ApplicationRunner`
implementations have been run, an entry in the `TaskRepository` that records the start
event is created. This event is triggered through `SmartLifecycle#start` being triggered
by the Spring Framework. This indicates to the system that all beans are ready for use and
comes before running any of the `CommandLineRunner` or `ApplicationRunner` implementations
provided by Spring Boot.
NOTE: The recording of a task will only occur upon the successful bootstrapping of an
`ApplicationContext`. If the context fails to bootstrap at all, the task's execution will
not be recorded.
NOTE: The recording of a task only occurs upon the successful bootstrapping of an
`ApplicationContext`. If the context fails to bootstrap at all, the task's run is not
recorded.
Upon completion of all of the `*Runner#run` calls from Spring Boot or the failure of an
`ApplicationContext` (indicated via a `ApplicationFailedEvent`), the task execution is
`ApplicationContext` (indicated by an `ApplicationFailedEvent`), the task execution is
updated in the repository with the results.
NOTE: If the application requires the `ApplicationContext` to be closed at the
completion of a task (all `*Runner#run` methods are called and the task
completion of a task (all `*Runner#run` methods have been called and the task
repository has been updated), set the property `spring.cloud.task.closecontext_enable`
to true.
@@ -62,161 +66,149 @@ consists of the following information:
|Field |Description
|`executionid`
|The unique id for the task's execution.
|The unique ID for the task's run.
|`exitCode`
|The exit code generated from an `ExitCodeExceptionMapper` implementation. If there is no
exit code generated, but an `ApplicationFailedEvent` is thrown, 1 is set. Otherwise, it's
|The exit code generated from an `ExitCodeExceptionMapper` implementation. If there is no
exit code generated but an `ApplicationFailedEvent` is thrown, 1 is set. Otherwise, it is
assumed to be 0.
|`taskName`
|The name for the task as determined by the configured `TaskNameResolver`.
|The name for the task, as determined by the configured `TaskNameResolver`.
|`startTime`
|The time the task was started as indicated by the `SmartLifecycle#start` call.
|The time the task was started, as indicated by the `SmartLifecycle#start` call.
|`endTime`
|The time the task was completed as indicated by the `ApplicationReadyEvent`.
|The time the task was completed, as indicated by the `ApplicationReadyEvent`.
|`exitMessage`
|Any information available at the time of exit. This can programmatically be set via a
|Any information available at the time of exit. This can programmatically be set by a
`TaskExecutionListener`.
|`errorMessage`
|If an exception is the cause of the end of the task (as indicated via an
`ApplicationFailedEvent`), the stack trace for that exception will be stored here.
|If an exception is the cause of the end of the task (as indicated by an
`ApplicationFailedEvent`), the stack trace for that exception is stored here.
|`arguments`
|A `List` of the string command line arguments as they were passed into the executable boot
application.
|A `List` of the string command line arguments as they were passed into the executable
boot application.
|===
[[features-lifecycle-exit-codes]]
=== Mapping Exit Codes
When a task completes, it will want to return an exit code to the OS. If we take a look
at our original example, we can see that we are not controlling that aspect of our
application. So if an exception is thrown, the JVM will return a code that may or may not
be of any use to you in the debugging of that.
When a task completes, it tries to return an exit code to the OS. If we take a look
at our <<getting-started-developing-first-task,original example>>, we can see that we are
not controlling that aspect of our application. So, if an exception is thrown, the JVM
returns a code that may or may not be of any use to you in debugging.
As such, Spring Boot provides an interface, `ExitCodeExceptionMapper` that allows you to
map uncaught exceptions to exit codes. This allows you to be able to indicate at that
level what went wrong. Also, by mapping exit codes in this manner, Spring Cloud Task will
record the exit code returned.
Consequently, Spring Boot provides an interface, `ExitCodeExceptionMapper`, that lets you
map uncaught exceptions to exit codes. Doing so lets you indicate, at the level of exit
codes, what went wrong. Also, by mapping exit codes in this manner, Spring Cloud Task
records the returned exit code.
If the task is terminated with a SIG-INT or a SIG-TERM, the exit code will be zero unless
If the task terminates with a SIG-INT or a SIG-TERM, the exit code is zero unless
otherwise specified within the code.
NOTE: While the task is running the exit code will be stored as a null in the repository.
Once complete the appropriate exit code will be stored based on the guidelines enumerated
above.
NOTE: While the task is running, the exit code is stored as a null in the repository.
Once the task completes, the appropriate exit code is stored based on the guidelines described
earlier in this section.
[[features-configuration]]
== Configuration
Spring Cloud Task provides an out of the box configuration as defined in the
`DefaultTaskConfigurer` and `SimpleTaskConfiguration`. This section will walk through
the defaults as well as how to customize Spring Cloud Task for your needs
Spring Cloud Task provides a ready-to-use configuration, as defined in the
`DefaultTaskConfigurer` and `SimpleTaskConfiguration` classes. This section walks through
the defaults and how to customize Spring Cloud Task for your needs.
[[features-data-source]]
=== DataSource
Spring Cloud Task utilizes a datasource for storing the results of task executions. By
default, we provide an in memory instance of H2 to provide a simple method of
bootstrapping development. However, in a production environment, you'll want to configure
your own `DataSource`.
Spring Cloud Task uses a datasource for storing the results of task executions. By
default, we provide an in-memory instance of H2 to provide a simple method of
bootstrapping development. However, in a production environment, you probably want to
configure your own `DataSource`.
If your application utilizes only a single `DataSource` and that will serve as both your
business schema as well as the task repository, all you need to do is provide any
`DataSource` (via Spring Boot's configuration conventions is the easiest way). This will
be automatically used by Spring Cloud Task for the repository.
If your application uses only a single `DataSource` and that serves as both your business
schema and the task repository, all you need to do is provide any `DataSource` (the
easiest way to do so is through Spring Boot's configuration conventions). This
`DataSource` is automatically used by Spring Cloud Task for the repository.
If your application utilizes more than one `DataSource`, you'll need to configure the
task repository with the appropriate `DataSource`. This customization can be done via an
implementation of the `TaskConfigurer`.
If your application uses more than one `DataSource`, you need to configure the task
repository with the appropriate `DataSource`. This customization can be done through an
implementation of `TaskConfigurer`.
[[features-table-prefix]]
=== Table Prefix
One modifiable property of the TaskRepository is the table prefix for the
task tables. By default they are all prefaced with `TASK_`.
TASK_EXECUTION and TASK_EXECUTION_PARAMS are two examples. However, there are
potential reasons to modify this prefix. If the schema names needs to be
prepended to the table names, or if more than one set of task tables is
needed within the same schema, then the table prefix will need to be changed.
This is done by setting the `spring.cloud.task.tablePrefix` to the prefix
that is required.
One modifiable property of `TaskRepository` is the table prefix for the task tables. By
default, they are all prefaced with `TASK_`. `TASK_EXECUTION` and `TASK_EXECUTION_PARAMS`
are two examples. However, there are potential reasons to modify this prefix. If the
schema name needs to be prepended to the table names or if more than one set of task
tables is needed within the same schema, you must change the table prefix. You can do so
by setting the `spring.cloud.task.tablePrefix` to the prefix you need, as follows:
```
spring.cloud.task.tablePrefix=<yourPrefix>
```
`spring.cloud.task.tablePrefix=yourPrefix`
[[features-table-initialization]]
=== Enable/Disable table initialization
In cases where you are creating the task tables and do not wish for
Spring Cloud Task to create them at task startup set the
`spring.cloud.task.initialize.enable` property to `false`. It is currently
defaulted to `true`.
In cases where you are creating the task tables and do not wish for Spring Cloud Task to
create them at task startup, set the `spring.cloud.task.initialize.enable` property to
`false`, as follows:
```
spring.cloud.task.initialize.enable=<true or false>
```
`spring.cloud.task.initialize.enable=false`
It defaults to `true`.
[[features-generated_task_id]]
=== Externally Generated Task Id
=== Externally Generated Task ID
In some cases a user wants to allow for the time difference between
when a task is requested and when the infrastructure actually launches it.
Spring Cloud Task allows a user to create a TaskExecution at the time the
task is requested. Then pass the execution ID of the generated TaskExecution
to the task so that it can update the TaskExecution through the task's lifecycle.
In some cases, you may want to allow for the time difference between when a task is
requested and when the infrastructure actually launches it. Spring Cloud Task lets you
create a `TaskExecution` when the task is requested. Then pass the execution ID of the
generated `TaskExecution` to the task so that it can update the `TaskExecution` through
the task's lifecycle.
The TaskExecution can be created by calling the `createTaskExecution` method on
an implementation of the TaskRepository that references the datastore storing
the TaskExecutions.
A `TaskExecution` can be created by calling the `createTaskExecution` method on an
implementation of the `TaskRepository` that references the datastore that holds
the `TaskExecution` objects.
In order to configure your Task to use a generated TaskExecutionId add the
In order to configure your Task to use a generated `TaskExecutionId`, add the
following property:
```
spring.cloud.task.executionid=<yourtaskId>
```
`spring.cloud.task.executionid=yourtaskId`
[[features-external_task_id]]
=== External Task Id
Spring Cloud Task allows a user to store an external task Id for each
TaskExecution. An example of this would be a task id that is provided by
Spring Cloud Task lets you store an external task ID for each
`TaskExecution`. An example of this would be a task ID provided by
Cloud Foundry when a task is launched on the platform.
In order to configure your Task to use a generated TaskExecutionId add the
In order to configure your Task to use a generated `TaskExecutionId`, add the
following property:
```
spring.cloud.task.external-execution-id=<externalTaskId>
```
`spring.cloud.task.external-execution-id=<externalTaskId>`
[[features-parent_task_id]]
=== Parent Task Id
Spring Cloud Task allows a user to store an parent task Id for each
TaskExecution. An example of this would be a task that executes another task
or tasks and the user would like to store what task launched the child tasks.
In order to configure your Task to set a parent TaskExecutionId add the
following property on the child task:
Spring Cloud Task lets you store a parent task ID for each `TaskExecution`. An example of
this would be a task that executes another task or tasks and you want to record which task
launched each of the child tasks. In order to configure your Task to set a parent
`TaskExecutionId` add the following property on the child task:
```
spring.cloud.task.parent-execution-id=<parentExecutionTaskId>
```
`spring.cloud.task.parent-execution-id=<parentExecutionTaskId>`
[[features-task-configurer]]
=== TaskConfigurer
The `TaskConfigurer` is a strategy interface allowing for users to customize the way
components of Spring Cloud Task are configured. By default, we provide the
`DefaultTaskConfigurer` that provides logical defaults (`Map` based in memory components
useful for development if no `DataSource` is provided and JDBC based components if there
is a `DataSource` available.
The `TaskConfigurer` is a strategy interface that lets you customize the way components of
Spring Cloud Task are configured. By default, we provide the `DefaultTaskConfigurer` that
provides logical defaults: `Map`-based in-memory components (useful for development if no
`DataSource` is provided) and JDBC based components (useful if there is a `DataSource`
available).
The `TaskConfigurer` allows the configuration of three main components:
The `TaskConfigurer` lets you configure three main components:
|===
|Component |Description |Default (provided by `DefaultTaskConfigurer`)
@@ -226,63 +218,66 @@ The `TaskConfigurer` allows the configuration of three main components:
|`SimpleTaskRepository`
|`TaskExplorer`
|The implementation of the `TaskExplorer` (a component for read only access to the task
|The implementation of the `TaskExplorer` (a component for read-only access to the task
repository) to be used.
|`SimpleTaskExplorer`
|`PlatformTransactionManager`
|A transaction manager to be used when executing updates for tasks.
|`DataSourceTransactionManager` if a `DataSource` is used,
|A transaction manager to be used when running updates for tasks.
|`DataSourceTransactionManager` if a `DataSource` is used.
`ResourcelessTransactionManager` if it is not.
|===
Customizing any of the above is accomplished via a custom implementation of the
`TaskConfigurer` interface. Typically, extending the `DefaultTaskConfigurer` (which is
provided out of the box if a `TaskConfigurer` is not found) and overriding the
required getter is sufficient, however, implementing your own from scratch may be
required.
You can customize any of the components described in the preceding table by creating a
custom implementation of the `TaskConfigurer` interface. Typically, extending the
`DefaultTaskConfigurer` (which is provided if a `TaskConfigurer` is not found) and
overriding the required getter is sufficient. However, implementing your own from scratch
may be required.
[[features-task-name]]
=== Task Name
In most cases, the name of the task will be the application name as configured via Spring
Boot. However, there are some cases, where you may want to map the run of a task to a
different name. Spring Data Flow is an example of this (where you want the task to be run
with the name of the task definition). Because of this, we offer the ability to customize
how the task is named via the `TaskNameResolver` interface.
In most cases, the name of the task is the application name as configured in Spring
Boot. However, there are some cases where you may want to map the run of a task to a
different name. Spring Cloud Data Flow is an example of this (because you probably want
the task to be run with the name of the task definition). Because of this, we offer the
ability to customize how the task is named, through the `TaskNameResolver` interface.
By default, Spring Cloud Task provides the `SimpleTaskNameResolver` which will use the
By default, Spring Cloud Task provides the `SimpleTaskNameResolver`, which uses the
following options (in order of precedence):
. A Spring Boot property (configured any of the ways Spring Boot allows)
. A Spring Boot property (configured in any of the ways Spring Boot allows) called
`spring.cloud.task.name`.
. The application name as resolved using Spring Boot's rules (obtained via
. The application name as resolved using Spring Boot's rules (obtained through
`ApplicationContext#getId`).
[[features-task-execution-listener]]
=== Task Execution Listener
Allows a user to register listeners for specific events that occur during the task
lifecycle. This is done by creating a class that implements the TaskExecutionListener
interface. The class that implements the `TaskExecutionListener` interface will be
notified for the following events:
`TaskExecutionListener` lets you register listeners for specific events that occur during
the task lifecycle. To do so, create a class that implements the
`TaskExecutionListener` interface. The class that implements the `TaskExecutionListener`
interface is notified of the following events:
. `onTaskStartup` - prior to the storing the `TaskExecution` into the `TaskRepository`
. `onTaskEnd` - prior to the updating of the `TaskExecution` entry in the `TaskRepository`
* `onTaskStartup`: Prior to storing the `TaskExecution` into the `TaskRepository`.
* `onTaskEnd`: Prior to updating the `TaskExecution` entry in the `TaskRepository` and
marking the final state of the task.
. `onTaskFailed` - prior to the `onTaskEnd` method being invoked when an unhandled
exception is thrown by the task.
* `onTaskFailed`: Prior to the `onTaskEnd` method being invoked when an unhandled
exception is thrown by the task.
Spring Cloud Task also allows a user add `TaskExecution` Listeners to methods within a bean
Spring Cloud Task also lets you add `TaskExecution` Listeners to methods within a bean
by using the following method annotations:
. `@BeforeTask` - prior to the storing the `TaskExecution` into the `TaskRepository`
. `@AfterTask` - prior to the updating of the `TaskExecution` entry in the `TaskRepository`
* `@BeforeTask`: Prior to the storing the `TaskExecution` into the `TaskRepository`
* `@AfterTask`: Prior to the updating of the `TaskExecution` entry in the `TaskRepository`
marking the final state of the task.
. `@FailedTask` - prior to the `@AfterTask` method being invoked when an unhandled
exception is thrown by the task.
* `@FailedTask`: Prior to the `@AfterTask` method being invoked when an unhandled
exception is thrown by the task.
```
The following example shows the three annotations in use:
[source,java]
---
public class MyBean {
@BeforeTask
@@ -297,69 +292,71 @@ marking the final state of the task.
public void methodC(TaskExecution taskExecution, Throwable throwable) {
}
}
```
---
[[features-task-execution-listener-Exceptions]]
==== Exceptions Thrown by Task Execution Listener
In the case that an exception is thrown by a `TaskExecutionListener` event handler,
all listener processing for that event handler will stop. For example: if three
`onTaskStartup` listeners have established and the first `onTaskStartup` event handler
throws an exception then the other two `onTaskStartup` methods will not be called. However the
other event handlers (onTaskEnd, onTaskFailed) for the
`TaskExecutionListeners` will be called.
If an exception is thrown by a `TaskExecutionListener` event handler, all listener
processing for that event handler stops. For example, if three `onTaskStartup` listeners
have started and the first `onTaskStartup` event handler throws an exception, the other
two `onTaskStartup` methods are not called. However, the other event handlers (`onTaskEnd`
and `onTaskFailed`) for the `TaskExecutionListeners` are called.
The exit code returned when a exception is thrown by a `TaskExecutionListener`
event handler will be the exit code that was reported by the https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/ExitCodeEvent.html[ExitCodeEvent]. If
no `ExitCodeEvent` is emitted then the Exception thrown will be evaluated to see
event handler is the exit code that was reported by the
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/ExitCodeEvent.html[ExitCodeEvent].
If no `ExitCodeEvent` is emitted, the Exception thrown is evaluated to see
if it is of type
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit[ExitCodeGenerator]
, if so it will return the exit code from the `ExitCodeGenerator` else one
will be returned.
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit[ExitCodeGenerator].
If so, it returns the exit code from the `ExitCodeGenerator`. Otherwise, `1`
is returned.
[[features-task-execution-listener-exit-messages]]
==== Exit Messages
A user is allowed to set the exit message for a task programmatically via a
`TaskExecutionListener`. This is done by setting the `TaskExecution's` `exitMessage`
that is passed into the `TaskExecutionListener`. For example if we want to use
a method that is annotated with @AfterTask `ExecutionListener` :
```
You can set the exit message for a task programmatically by using a
`TaskExecutionListener`. This is done by setting the `TaskExecution's` `exitMessage`,
which then gets passed into the `TaskExecutionListener`. The following example shows
a method that is annotated with the `@AfterTask` `ExecutionListener` :
[source,java]
@AfterTask
public void afterMe(TaskExecution taskExecution) {
taskExecution.setExitMessage("AFTER EXIT MESSAGE");
}
```
Since a `ExitMessage` can be set at any of the listener events (onTaskStartup,
onTaskFailed, and onTaskEnd) the order of precedence is:
. onTaskEnd
. onTaskFailed
. onTaskStartup
An `ExitMessage` can be set at any of the listener events (`onTaskStartup`,
`onTaskFailed`, and `onTaskEnd`). The order of precedence for the three listeners follows:
For example if a user sets a `exitMessage` for the `onTaskStartup` and `onTaskFailed`
listeners and the task ends without failing then the `exitMessage` from the `onTaskStartup`
will be stored in the repo, else if a failure occurs then the `exitMessage` from
the `onTaskFailed` will be stored. Also if a user sets the `exitMessage` with a
`onTaskEnd` listener then the `exitMessage` from the `onTaskEnd` will supersede
. `onTaskEnd`
. `onTaskFailed`
. `onTaskStartup`
For example, if you set an `exitMessage` for the `onTaskStartup` and `onTaskFailed`
listeners and the task ends without failing, the `exitMessage` from the `onTaskStartup`
is stored in the repository. Otherwise, if a failure occurs, the `exitMessage` from
the `onTaskFailed` is stored. Also if you set the `exitMessage` with an
`onTaskEnd` listener, the `exitMessage` from the `onTaskEnd` supersedes
the exit messages from both the `onTaskStartup` and `onTaskFailed`.
=== Restricting Spring Cloud Task Instances
Allows a user to establish that only one task with a given task name can be run
at a time. To do this the user establishes the <<features-task-name, task name>>
and sets `spring.cloud.task.singleInstanceEnabled=true` for each task execution.
While the first task execution is running, any other time user tries to run
a task with the same <<features-task-name, task name>> and
`spring.cloud.task.singleInstanceEnabled=true` the task will fail with the following
error message `Task with name "application" is already running.` The default
for `spring.cloud.task.singleInstanceEnabled` is `false`.
```
spring.cloud.task.singleInstanceEnabled=<true or false>
```
In order for this feature to be used you must include the following Spring
Integration dependencies to your application:
Spring Cloud Task lets you establish that only one task with a given task name can be run
at a time. To do so, you need to establish the <<features-task-name, task name>> and set
`spring.cloud.task.singleInstanceEnabled=true` for each task execution. While the first
task execution is running, any other time you try to run a task with the same
<<features-task-name, task name>> and`spring.cloud.task.singleInstanceEnabled=true`, the
task fails with the following error message: `Task with name "application" is already
running.` The default value for `spring.cloud.task.singleInstanceEnabled` is `false`. The
following example shows how to set `spring.cloud.task.singleInstanceEnabled` to `true`:
`spring.cloud.task.singleInstanceEnabled=true or false`
To use this feature, you must add the following Spring Integration dependencies to your
application:
[source,xml]
---
<dependency>

View File

@@ -4,54 +4,56 @@
[[partintro]]
--
If you're just getting started with Spring Cloud Task, this is the section
for you! Here we answer the basic "`what?`", "`how?`" and "`why?`" questions. You'll
find a gentle introduction to Spring Cloud Task. We'll then build our first Spring Cloud
Task application, discussing some core principles as we go.
If you are just getting started with Spring Cloud Task, you should read this section.
Here, we answer the basic "`what?`", "`how?`", and "`why?`" questions. We start with a
gentle introduction to Spring Cloud Task. We then build a Spring Cloud Task application,
discussing some core principles as we go.
--
[[getting-started-introducing-spring-cloud-task]]
== Introducing Spring Cloud Task
Spring Cloud Task makes it easy to create short lived microservices. We provide
capabilities that allow short lived JVM processes to be executed on demand in a production
Spring Cloud Task makes it easy to create short-lived microservices. It provides
capabilities that let short lived JVM processes be executed on demand in a production
environment.
[[getting-started-system-requirements]]
== System Requirements
You need Java installed (Java 7 or better, we recommend Java 8) and to build you need to have Maven installed as well.
You need to have Java installed (Java 8 or better). To build, you need to have Maven
installed as well.
=== Database Requirements
Spring Cloud Task uses a relational database to store the results of an executed task.
While you can begin developing a task without a database (the status of the task is logged
as part of the task repository's updates), for production environments, you'll want to
utilize a supported database. Below is a list of the ones currently supported:
as part of the task repository's updates), for production environments, you want to
use a supported database. Spring Cloud Task currently supports the following databases:
- DB2
- H2
- HSQLDB
- MySql
- Oracle
- Postgres
- SqlServer
* DB2
* H2
* HSQLDB
* MySql
* Oracle
* Postgres
* SqlServer
[[getting-started-developing-first-task]]
== Developing your first Spring Cloud Task application
== Developing Your First Spring Cloud Task Application
A good place to start is with a simple "Hello World!" application so we'll create the
Spring Cloud Task equivalent to highlight the features of the framework. We'll use Apache
Maven as a build tool for this project since most IDEs have good support for it.
A good place to start is with a simple "`Hello, World!`" application, so we create the
Spring Cloud Task equivalent to highlight the features of the framework. Most IDEs have
good support for Apache Maven, so we use it as the build tool for this project.
NOTE: The spring.io web site contains many “Getting Started” guides that use Spring Boot.
If youre looking to solve a specific problem; check there first. You can shortcut the
steps below by going to start.spring.io and creating a new project. This will
automatically generate a new project structure so that you can start coding right the way.
Check the documentation for more details.
NOTE: The spring.io web site contains many https://spring.io/guides[“`Getting Started`”
guides] that use Spring Boot. If you need to solve a specific problem, check there first.
You can shortcut the following steps by going to the
http://start.spring.io/[Spring Initializr] and creating a new project. Doing so
automatically generates a new project structure so that you can start coding right away.
We recommend experimenting with the Spring Initializr to become familiar with it.
Before we begin, open a terminal to check that you have valid versions of Java and Maven
installed.
installed, as shown in the following two listings:
[source]
$ java -version
@@ -65,14 +67,15 @@ Apache Maven 3.2.3 (33f8c3e1027c3ddde99d3cdebad2656a31e8fdf4; 2014-08-11T15:58:1
Maven home: /usr/local/Cellar/maven/3.2.3/libexec
Java version: 1.8.0_31, vendor: Oracle Corporation
NOTE: This sample needs to be created in its own folder. Subsequent instructions assume
you have created a suitable folder and that it is your "current directory".
NOTE: This sample needs to be created in its own folder. Subsequent instructions assume
you have created a suitable folder and that it is your "`current directory.`"
[[getting-started-creating-the-pom]]
=== Creating the POM
We need to start by creating a Maven `pom.xml` file. The `pom.xml` is the recipe that
will be used to build your project. Open your favorite text editor and add the following:
We need to start by creating a Maven `pom.xml` file. The `pom.xml` file contains the
recipe that Maven uses to build your project. To create the pom.xml file, open your
favorite text editor and add the following:
[code,xml]
----
@@ -116,29 +119,30 @@ will be used to build your project. Open your favorite text editor and add the
</project>
----
This should give you a working build. You can test it out by running `mvn package` (you
can ignore the "jar will be empty - no content was marked for inclusion!" warning for
now).
Creating a `pom.xml` file with the preceding content should give you a working build. You
can test it by running `mvn package` (for now, you can ignore the "jar will be empty - no
content was marked for inclusion!" warning ).
NOTE: At this point you could import the project into an IDE (most modern Java IDE's
include built-in support for Maven). For simplicity we will continue to use a plain text
NOTE: At this point, you could import the project into an IDE (most modern Java IDE's
include built-in support for Maven). For simplicity, we continue to use a plain text
editor for this example.
[[getting-started-adding-classpath-dependencies]]
=== Adding classpath dependencies
A Spring Cloud Task is made up of a Spring Boot application that is expected to end. In
our POM above, we created the shell of a Spring Boot application from a dependency
perspective by setting our parent to use the `spring-boot-starter-parent`.
A Spring Cloud Task is made up of a Spring Boot application that is expected to end. In
the `pom.xml` file we showed earlier, we created the shell of a Spring Boot application by
setting our parent to use the `spring-boot-starter-parent`.
Spring Boot provides a number of additional "Starter POMs". Some of which are appropriate
for use within tasks (`spring-boot-starter-batch`, `spring-boot-starter-jdbc`, etc) and
some may not be ('spring-boot-starter-web` is probably not going to be used in a task).
The indicator of if a starter makes sense or not comes down to if the resulting
application will end (batch based applications typically end, the
`spring-boot-starter-web` dependency bootstraps a servlet container which probably wont').
Spring Boot provides a number of additional "`Starter POMs`". Some of them are appropriate
for use within tasks (`spring-boot-starter-batch`, `spring-boot-starter-jdbc`, and
others), and some may not be ('spring-boot-starter-web` is probably not going to be used
in a task). The best indicator of which starter makes sense is whether the resulting
application should end. Batch-based applications typically end. Conversely, the
`spring-boot-starter-web` dependency bootstraps a servlet container, which better suits
applications that continue.
For this example, we'll only need to add a single additional dependency, the one for
For this example, we need only to add a single additional dependency -- the one for
Spring Cloud Task itself:
[source,xml]
@@ -149,11 +153,12 @@ Spring Cloud Task itself:
</dependency>
[[getting-started-writing-the-code]]
=== Writing the code
=== Writing the Code
To finish our application, we need to create a single Java file. Maven will compile the
sources from `src/main/java` by default so you need to create that folder structure. Then
add a file named `src/main/java/com/example/SampleTask.java`:
To finish our application, we need to create a single Java file. By default, Maven
compiles the sources from `src/main/java`, so you need to create that folder structure.
Then you need to add a file named `src/main/java/com/example/SampleTask.java`, as shown
in the following example:
[source,java]
----
@@ -181,20 +186,21 @@ public class SampleTask {
@Override
public void run(String... strings) throws Exception {
System.out.println("Hello World!");
System.out.println("Hello, World!");
}
}
}
----
While it may not look like much, quite a bit is going on. To read more about the Spring
Boot specifics, take a look at their reference documentation here:
http://docs.spring.io/spring-boot/docs/current/reference/html/[http://docs.spring.io/spring-boot/docs/current/reference/html/]
While it may seem small, quite a bit is going on. For more about Spring
Boot specifics, see the
http://docs.spring.io/spring-boot/docs/current/reference/html/[Spring Boot reference documentation].
We'll also need to create an `application.properties` in `src/main/resources`. We'll
configure two properties in it: the application name (which is translated to the task name)
and we'll set the logging for spring cloud task to `DEBUG` so that we can see what's going
on:
We also need to create an `application.properties` file in `src/main/resources`. We need
to configure two properties in `application.properties`: We need to set the application
name (which is translated to the task name), and we need to set the logging for Spring
Cloud Task to `DEBUG` so that we can see what's going on. The following example shows how
to do both:
[source]
----
@@ -205,23 +211,23 @@ spring.application.name=helloWorld
[[getting-started-at-task]]
==== The @EnableTask annotation
The first non boot annotation in our example is the `@EnableTask` annotation. This class
level annotation tells Spring Cloud Task to bootstrap it's functionality. This occurs by
importing an additional configuration class, `SimpleTaskConfiguration` by default. This
The first non-boot annotation in our example is the `@EnableTask` annotation. This
class-level annotation tells Spring Cloud Task to bootstrap it's functionality. By
default, it imports an additional configuration class (`SimpleTaskConfiguration`). This
additional configuration registers the `TaskRepository` and the infrastructure for its
use.
Out of the box, the `TaskRepository` will use an in memory `Map` to record the results
of a task. Obviously this isn't a practical solution for a production environment since
the `Map` goes away once the task ends. However, for a quick getting started
experience we use this as a default as well as echoing to the logs what is being updated
in that repository. Later in this documentation we'll cover how to customize the
configuration of the pieces provided by Spring Cloud Task.
Out of the box, the `TaskRepository` uses an in-memory `Map` to record the results
of a task. A `Map` is not a practical solution for a production environment, since
the `Map` goes away once the task ends. However, for a quick getting-started
experience, we use this as a default as well as echoing to the logs what is being updated
in that repository. In the <<features-configuration>> section (later in this
documentation), we cover how to customize the configuration of the pieces provided by
Spring Cloud Task.
When our sample application is run, Spring Boot will launch our
`HelloWorldCommandLineRunner` outputting our "Hello World!" message to standard out. The
`TaskLifecyceListener` will record the start of the task and the end of the task in the
repository.
When our sample application runs, Spring Boot launches our `HelloWorldCommandLineRunner`
and outputs our "`Hello, World!`" message to standard out. The `TaskLifecyceListener`
records the start of the task and the end of the task in the repository.
[[getting-started-main-method]]
==== The main method
@@ -233,25 +239,25 @@ Spring Boot documentation.
[[getting-started-clr]]
==== The CommandLineRunner
In Spring, there are many ways to bootstrap an application's logic. Spring Boot provides
a convenient method of doing so in an organized manner via their `*Runner` interfaces
(`CommandLineRunner` or `ApplicationRunner`). A well behaved task will bootstrap any
logic via one of these two runners.
Spring includes many ways to bootstrap an application's logic. Spring Boot provides
a convenient method of doing so in an organized manner through its `*Runner` interfaces
(`CommandLineRunner` or `ApplicationRunner`). A well behaved task can bootstrap any
logic by using one of these two runners.
The lifecycle of a task is considered from before the `*Runner#run` methods are executed
to once they are all complete. Spring Boot allows an application to use multiple
`*Runner` implementation and Spring Cloud Task doesn't attempt to impede on this convention.
to once they are all complete. Spring Boot lets an application use multiple
`*Runner` implementations, as does Spring Cloud Task.
NOTE: Any processing bootstrapped from mechanisms other than a `CommandLineRunner` or
`ApplicationRunner` (using `InitializingBean#afterPropertiesSet` for example) will not be
`ApplicationRunner` (by using `InitializingBean#afterPropertiesSet` for example) is not
recorded by Spring Cloud Task.
[[getting-started-running-the-example]]
=== Running the example
=== Running the Example
At this point, your application should work. Since this application is Spring Boot based,
we can run it from the command line via the command `$ mvn spring-boot:run` from the root
of our applicaiton:
At this point, our application should work. Since this application is Spring Boot-based,
we can run it from the command line by using `$ mvn spring-boot:run` from the root
of our application, as shown (with its output) in the following example:
[source]
----
@@ -274,19 +280,19 @@ $ mvn clean spring-boot:run
2016-01-25 11:08:10.226 INFO 12943 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a2c3676: startup date [Mon Jan 25 11:08:10 CST 2016]; root of context hierarchy
2016-01-25 11:08:11.051 INFO 12943 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-01-25 11:08:11.065 INFO 12943 --- [ main] o.s.c.t.r.support.SimpleTaskRepository : Creating: TaskExecution{executionId=0, externalExecutionID='null', exitCode=0, taskName='application', startTime=Mon Jan 25 11:08:11 CST 2016, endTime=null, statusCode='null', exitMessage='null', arguments=[]}
Hello World!
Hello, World!
2016-01-25 11:08:11.071 INFO 12943 --- [ main] com.example.SampleTask : Started SampleTask in 1.095 seconds (JVM running for 3.826)
2016-01-25 11:08:11.220 INFO 12943 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a2c3676: startup date [Mon Jan 25 11:08:10 CST 2016]; root of context hierarchy
2016-01-25 11:08:11.222 INFO 12943 --- [ Thread-1] o.s.c.t.r.support.SimpleTaskRepository : Updating: TaskExecution{executionId=0, externalExecutionID='null', exitCode=0, taskName='application', startTime=Mon Jan 25 11:08:11 CST 2016, endTime=Mon Jan 25 11:08:11 CST 2016, statusCode='null', exitMessage='null', arguments=[]}
2016-01-25 11:08:11.222 INFO 12943 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
----
If you notice, there are three lines of interest in the above output:
The preceding output has three lines that of interest to us here:
* `SimpleTaskRepository` logged out the creation of the entry in the `TaskRepository`.
* The execution of our `CommandLineRunner`, demonstrated by the "Hello World!" output.
* `SimpleTaskRepository` logging the completion of the task in the `TaskRepository`.
* `SimpleTaskRepository` logged the creation of the entry in the `TaskRepository`.
* The execution of our `CommandLineRunner`, demonstrated by the "`Hello, World!`" output.
* `SimpleTaskRepository` logs the completion of the task in the `TaskRepository`.
NOTE: A simple task application can be found in the samples module
of the Spring Cloud Task Project
NOTE: A simple task application can be found in the samples module of the Spring Cloud
Task Project
https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/timestamp[here].

View File

@@ -1,5 +1,5 @@
= Spring Cloud Task Reference Guide
Michael Minella, Glenn Renfro
Michael Minella, Glenn Renfro, Jay Bryant
:doctype: book
:toc:
:toclevels: 4

View File

@@ -4,41 +4,41 @@
[[task-documentation-about]]
This section provides a brief overview of the Spring Cloud Task reference documentation.
Think of it as a map for the rest of the document. You can read this reference guide in a
linear fashion, or you can skip sections if something doesn't interest you.
Think of it as a map for the rest of the document. You can read this reference guide in a
linear fashion or you can skip sections if something does not interest you.
== About the documentation
The Spring Cloud Task reference guide is available as {spring-cloud-task-docs}/html[html],
The Spring Cloud Task reference guide is available in {spring-cloud-task-docs}/html[html],
{spring-cloud-task-docs}/pdf/spring-cloud-task-reference.pdf[pdf]
and {spring-cloud-task-docs}/epub/spring-cloud-task-reference.epub[epub] documents. The latest copy
is available at {spring-cloud-task-docs-current}.
and {spring-cloud-task-docs}/epub/spring-cloud-task-reference.epub[epub] formats. The
latest copy is available at {spring-cloud-task-docs-current}.
Copies of this document may be made for your own use and for
distribution to others, provided that you do not charge any fee for such copies and
further provided that each copy contains this Copyright Notice, whether distributed in
print or electronically.
Copies of this document may be made for your own use and for distribution to others,
provided that you do not charge any fee for such copies and further provided that each
copy contains this Copyright Notice, whether distributed in print or electronically.
[[task-documentation-getting-help]]
== Getting help
Having trouble with Spring Cloud Task, We'd like to help!
Having trouble with Spring Cloud Task? We would like to help!
* Ask a question - we monitor http://stackoverflow.com[stackoverflow.com] for questions
tagged with http://stackoverflow.com/tags/spring-cloud-task[`spring-cloud-task`].
* Report bugs with Spring Cloud Task at https://github.com/spring-cloud/spring-cloud-task/issues.
* Ask a question. We monitor http://stackoverflow.com[stackoverflow.com] for questions
tagged with http://stackoverflow.com/tags/spring-cloud-task[`spring-cloud-task`].
* Report bugs with Spring Cloud Task at
https://github.com/spring-cloud/spring-cloud-task/issues.
NOTE: All of Spring Cloud Task is open source, including the documentation! If you find problems
with the docs; or if you just want to improve them, please {github-code}[get involved].
NOTE: All of Spring Cloud Task is open source, including the documentation. If you find
a problem with the docs or if you just want to improve them, please {github-code}[get
involved].
[[task-documentation-first-steps]]
== First Steps
If you're just getting started with Spring Cloud Task, or 'Spring' in general,
<<getting-started.adoc#getting-started, this is the place to start!>>
* *From scratch:*
<<getting-started.adoc#getting-started-introducing-spring-cloud-task, Overview>> |
<<getting-started.adoc#getting-started-system-requirements, Requirements>>
* *Tutorial:*
<<getting-started.adoc#getting-started-developing-first-task, First application>>
* *Running your example:*
<<getting-started.adoc#getting-started-running-the-example, Running your application>>
If you are just getting started with Spring Cloud Task or with 'Spring' in general, we
suggesting reading the <<getting-started.adoc#getting-started>> chapter.
To get started from scratch, read the following sections:
* "`<<getting-started.adoc#getting-started-introducing-spring-cloud-task>>`"
* "`<<getting-started.adoc#getting-started-system-requirements>>`"
To follow the tutorial, read
"`<<getting-started.adoc#getting-started-developing-first-task>>`"
To run your example, read
"`<<getting-started.adoc#getting-started-running-the-example>>`"

View File

@@ -3,40 +3,39 @@
[[partintro]]
--
A task by itself can be useful, but it's the integration of a task into a larger ecosystem
that allows it to be useful for more complex processing and orchestration. This section
covers the integration options for Spring Cloud Task and Spring Cloud Stream.
A task by itself can be useful, but integration of a task into a larger ecosystem lets it
be useful for more complex processing and orchestration. This section
covers the integration options for Spring Cloud Task with Spring Cloud Stream.
--
[[stream-integration-launching-sink]]
== Launching a task from a Spring Cloud Stream
== Launching a Task from a Spring Cloud Stream
Allows a user to launch tasks from a stream. This is done by creating a sink that
listens for a message that contains a `TaskLaunchRequest` as its payload. The
TaskLaunchRequest contains:
You can launch tasks from a stream. To do so, create a sink that listens for a message
that contains a `TaskLaunchRequest` as its payload. The `TaskLaunchRequest` contains:
* uri - to the task artifact that is to be executed.
* applicationName - the name that will be associated with the task. If no
applicationName is set the TaskLaunchRequest will generate a task name
comprised of the following: `Task-<UUID>`
* commandLineArguments - a list containing the command line arguments for the
* `uri`: To the task artifact that is to be executed.
* `applicationName`: The name that is associated with the task. If no
applicationName is set, the `TaskLaunchRequest` generates a task name
comprised of the following: `Task-<UUID>`.
* `commandLineArguments`: A list containing the command line arguments for the task.
* `environmentProperties`: A map containing the environment variables to be used by the
task.
* environmentProperties - a map containing the environment variables to be used
by the task
* deploymentProperties - a map containing the properties that will be used by
the deployer to deploy the task.
* `deploymentProperties`: A map containing the properties that are used by the deployer to
deploy the task.
NOTE: If the payload is of a different type then the sink will throw an exception.
NOTE: If the payload is of a different type, the sink throws an exception.
For example a stream can be created that has a processor that takes in data from a
http source and creates a `GenericMessage` that contains the `TaskLaunchRequest` and sends
For example, a stream can be created that has a processor that takes in data from an
HTTP source and creates a `GenericMessage` that contains the `TaskLaunchRequest` and sends
the message to its output channel. The task sink would then receive the message from its
input channnel and then launch the task.
To create a taskSink a user needs to only create a spring boot app that includes the
following annotation `EnableTaskLauncher`. The code would look something like this:
To create a taskSink, you need only create a Spring Boot application that includes the
`EnableTaskLauncher` annotation, as shown in the following example:
```
[source,java]
----
@SpringBootApplication
@EnableTaskLauncher
public class TaskSinkApplication {
@@ -44,51 +43,55 @@ public class TaskSinkApplication {
SpringApplication.run(TaskSinkApplication.class, args);
}
}
```
----
A sample Sink and Processor have been made available to you in the samples module
of the Spring Cloud Task project. To install these samples into your local maven
repository execute a maven build from the `spring-cloud-task-samples` directory with the
property `skipInstall` set to false. For example:
`mvn clean install`.
The https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples[samples
module] of the Spring Cloud Task project contains a sample Sink and Processor. To install
these samples into your local maven repository, run a maven build from the
`spring-cloud-task-samples` directory with the `skipInstall` property set to `false`, as
shown in the following example:
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.
`mvn clean install`
NOTE: The `maven.remoteRepositories.springRepo.url` property must be set to the location
of the remote repository in which the über-jar is located. If not set, there is no remote
repository, so it relies upon the local repository only.
[[stream-integration-launching-sink-dataflow]]
=== Spring Cloud Data Flow
To create a stream in Spring Cloud Data Flow first we would want to register the Task Sink
Application we created. In the example below we are registering the Processor and Sink
sample applications using the Spring Cloud Data Flow shell:
To create a stream in Spring Cloud Data Flow, you must first register the Task Sink
Application we created. In the following example, we are registering the Processor and
Sink sample applications by using the Spring Cloud Data Flow shell:
```
[source,bash]
----
app register --name taskSink --type sink --uri maven://io.spring.cloud:tasksink:<version>
app register --name taskProcessor --type processor --uri maven:io.spring.cloud:taskprocessor:<version>
```
----
Creating a stream from the Spring Cloud Data Flow shell would look like this:
The following example shows how to create a stream from the Spring Cloud Data Flow shell:
```
[source,bash]
stream create foo --definition "http --server.port=9000|taskProcessor|taskSink" --deploy
```
[[stream-integration-events]]
== Spring Cloud Task Events
Spring Cloud Task provides the ability to emit events via Spring Cloud Stream channel
when the task is executed via a Spring Cloud Stream channel. A task listener is used to
publish the `TaskExecution` on a message channel named `task-events`. This feature is
autowired into any task that has `spring-cloud-stream` on its classpath in addition to the
`spring-cloud-stream` and a task defined.
Spring Cloud Task provides the ability to emit events through a Spring Cloud Stream
channel when the task is run through a Spring Cloud Stream channel. A task listener is
used to publish the `TaskExecution` on a message channel named `task-events`. This feature
is autowired into any task that has `spring-cloud-stream`, `spring-cloud-stream-<binder>`,
and a defined task on its classpath.
NOTE: To disable the event emitting listener, set the property
`spring.cloud.task.events.enabled` to `false`.
NOTE: To disable the event emitting listener, set the `spring.cloud.task.events.enabled`
property to `false`.
With the appropriate classpath defined, a simple task like this:
With the appropriate classpath defined, the following task emits the `TaskExecution` as an
event on the `task-events` channel (at both the start and the end of the task):
```
[source, java]
----
@SpringBootApplication
@EnableTask
public class TaskEventsApplication {
@@ -111,87 +114,81 @@ public class TaskEventsApplication {
}
}
}
```
will emit the `TaskExecution` as an event on the `task-events` channel (both at the start
and end of the task).
NOTE: Configuration of the content type may be required via
`--spring.cloud.stream.bindings.task-events.contentType=<CONTENT_TYPE>` if the processor
or sink downstream does not have the spring-cloud-task-core jar on its classpath.
----
NOTE: A binder implementation is also required to be on the classpath.
NOTE: A sample task event application can be found in the samples module
of the Spring Cloud Task Project
of the Spring Cloud Task Project,
https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/task-events[here].
[[stream-integration-disable-task-events]]
=== Disabling Specific Task Events
To task events, the `spring.cloud.task.events.enabled` property can be set to `false`.
To disable task events, you can set the `spring.cloud.task.events.enabled` property to
`false`.
[[stream-integration-batch-events]]
== Spring Batch Events
When executing a Spring Batch job via a task, Spring Cloud Task can be configured to emit
informational messages based on the Spring Batch listeners available in Spring Batch.
Specifically the following Spring Batch listeners are autoconfigured into each batch job and
emit messages on the associated Spring Cloud Stream channels when run via Spring Cloud
Task:
When executing a Spring Batch job through a task, Spring Cloud Task can be configured to
emit informational messages based on the Spring Batch listeners available in Spring Batch.
Specifically, the following Spring Batch listeners are autoconfigured into each batch job
and emit messages on the associated Spring Cloud Stream channels when run through Spring
Cloud Task:
* `JobExecutionListener` - `job-execution-events`
* `StepExecutionListener` - `step-execution-events`
* `ChunkListener` - `chunk-events`
* `ItemReadListener` - `item-read-events`
* `ItemProcessListener` - `item-process-events`
* `ItemWriteListener` - `item-write-events`
* `SkipListener` - `skip-events`
* `JobExecutionListener` listens for `job-execution-events`
* `StepExecutionListener` listens for `step-execution-events`
* `ChunkListener` listens for `chunk-events`
* `ItemReadListener` listens for `item-read-events`
* `ItemProcessListener` listens for `item-process-events`
* `ItemWriteListener` listens for `item-write-events`
* `SkipListener` listens for `skip-events`
The above listeners are autoconfigured into any `AbstractJob` when the appropriate
beans exist in the context (a `Job` and a `TaskLifecycleListener`). Configuration to
These listeners are autoconfigured into any `AbstractJob` when the appropriate
beans (a `Job` and a `TaskLifecycleListener`) exist in the context. Configuration to
listen to these events is handled the same way binding to any other Spring
Cloud Stream channel is done. Our task (the one running the batch job) serves as a
`Source`, with the listening applications serving as either a `Processor` or `Sink`.
`Source`, with the listening applications serving as either a `Processor` or a `Sink`.
An example could be to have an application listening to the `job-execution-events` channel
for the start and stop of a job. To configure the listening application, you'd configure
the input to be `job-execution-events` as follows
for the start and stop of a job. To configure the listening application, you would
configure the input to be `job-execution-events` as follows:
```
spring.cloud.stream.bindings.input.destination=job-execution-events
```
`spring.cloud.stream.bindings.input.destination=job-execution-events`
NOTE: A binder implementation is also required to be on the classpath.
NOTE: A sample batch event application can be found in the samples module
of the Spring Cloud Task Project
of the Spring Cloud Task Project,
https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/batch-events[here].
=== Sending Batch Events to different channels
=== Sending Batch Events to Different Channels
One of the options that Spring Cloud Task offers for batch events is the ability to alter the channel to which a
specific listener can emit its messages. To do this use the following configuration:
`spring.cloud.stream.bindings.<the channel>.destination=<new destination>`.
For example: If StepExecutionListener needs to emit its messages to another channel `my-step-execution-events`
instead of the default `step-execution-events` the following configuration can be added:
One of the options that Spring Cloud Task offers for batch events is the ability to alter
the channel to which a specific listener can emit its messages. To do so, use the
following configuration:
`spring.cloud.stream.bindings.<the channel>.destination=<new destination>`. For example,
if `StepExecutionListener` needs to emit its messages to another channel called
`my-step-execution-events` instead of the default `step-execution-events`, you can add the
following configuration:
```
spring.cloud.stream.bindings.step-execution-events.destination=my-step-execution-events`
```
`spring.cloud.stream.bindings.step-execution-events.destination=my-step-execution-events`
=== Disabling Batch Events
To disable the all batch event listener functionality, use the following configuration:
To disable the listener functionality for all batch events, use the following
configuration:
```
spring.cloud.task.batch.events.enabled=false
```
`spring.cloud.task.batch.events.enabled=false`
To disable a specific batch event, use the following configuration:
To disable a specific batch event use the following configuration:
`spring.cloud.task.batch.events.<batch event listener>.enabled=false`:
```
The following listing shows individual listeners that you can disable:
[source,bash]
----
spring.cloud.task.batch.events.job-execution.enabled=false
spring.cloud.task.batch.events.step-execution.enabled=false
spring.cloud.task.batch.events.chunk.enabled=false
@@ -199,12 +196,14 @@ spring.cloud.task.batch.events.item-read.enabled=false
spring.cloud.task.batch.events.item-process.enabled=false
spring.cloud.task.batch.events.item-write.enabled=false
spring.cloud.task.batch.events.skip.enabled=false
```
----
=== Emit Order for Batch Events
By default batch events have `Ordered.LOWEST_PRECEDENCE` , to change this value ( for example to 5 ) use the following configuration:
By default, batch events have `Ordered.LOWEST_PRECEDENCE`. To change this value (for
example, to 5 ), use the following configuration:
```
[source,bash]
----
spring.cloud.task.batch.events.job-execution-order=5
spring.cloud.task.batch.events.step-execution-order=5
spring.cloud.task.batch.events.chunk-order=5
@@ -212,4 +211,4 @@ spring.cloud.task.batch.events.item-read-order=5
spring.cloud.task.batch.events.item-process-order=5
spring.cloud.task.batch.events.item-write-order=5
spring.cloud.task.batch.events.skip-order=5
```
----