Spring Cloud Task Reference Guide

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.

Part I. Preface

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.

1. About the documentation

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.

Part II. Getting started

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.

4. 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
environment.

5. 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.

5.1 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:

H2

HSQLDB

MySql

Oracle

Postgres

6. 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.

Note

The spring.io web site contains many “Getting Started” guides that use Spring Boot.
If you’re 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.

Before we begin, open a terminal to check that you have valid versions of Java and Maven
installed.

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).

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
editor for this example.

6.2 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.

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').

For this example, we’ll only need to add a single additional dependency, the one for
Spring Cloud Task itself:

6.3 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:

6.3.1 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
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.

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.

6.3.2 The main method

The main method serves as the entry point to any java application. Our main method
delegates to Spring Boot’s SpringApplication class. You can read more about it in the
Spring Boot documentation.

6.3.3 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 manor via their *Runner interfaces
(CommandLineRunner or ApplicationRunner). A well behaved task will bootstrap any
logic via 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.

Note

Any processing bootstrapped from mechanisms other than a CommandLineRunner or
ApplicationRunner (using InitializingBean#afterPropertiesSet for example) will not be
recorded by Spring Cloud Task.

6.4 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:

SimpleTaskRepository logged out the creation of the entry in the TaskRepository.

The execution of our CommandLineRunner, demonstrated by the "Helo World!" output.

SimpleTaskREpository logging the completion of the task in the TaskRepository.

Part III. Features

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.

7. 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.

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.

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.

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
annotation).

At the beginning of a task, an entry in the TaskRepository is created recording the
start event. This event is triggered via the ContextRefreshEvent being triggered by
Spring Framework.

Note

As Spring Cloud Task is expected to consist of a single application context. If
multiple application contexts are used (parent/child relationships for example), the first
ContextRefreshEvent that is published by Spring will be recorded as the start of the
task.

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.

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
updated in the repository with the results.

7.1 The TaskExecution

The information stored in the TaskRepository is modeled in the TaskExecution class and
consists of the following information:

Field

Description

executionid

The unique id for the task’s execution.

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
assumed to be 0.

taskName

The name for the task as determined by the configured TaskNameResolver.

starTime

The time the task was started as indicated by the ContextRefreshEvent.

endTime

The time the task was completed as indicated by the ContextClosedEvent.

exitMessage

Any information available at the time of exit. 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.

parameters

A List of the string parameters as they were passed into the executable boot
application.

7.2 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.

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 manor, Spring Cloud Task will
record the exit code returned.

8. 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

8.1 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.

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 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.

8.2 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 allows the configuration of three main components:

Component

Description

Default (provided by DefaultTaskConfigurer)

TaskRepository

The implementation of the TaskRepository to be used.

SimpleTaskRepository

TaskExplorer

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,
ResourcelessTransactionManager if it is not.

8.3 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.

By default, Spring Cloud Task provides the SimpleTaskNameResolver which will use the
following options (in order of precedence):

A Spring Boot property (configured any of the ways Spring Boot allows)
spring.cloud.task.name.

The application name as resolved using Spring Boot’s rules (obtained via
ApplicationContext#getId).

Part IV. Appendices

9. Task repository schema

This appendix provides an ERD for the database schema used in the task repository.

10. Building this documentation

This project uses Maven to generate this documentation. To generate it for yourself,
execute the command: $ ./mvnw clean package -P full.