90-character pass for scalability.adoc
I removed extraneous characters from non-code lines and arranged the non-code lines to fit into 90 characters.
This commit is contained in:
committed by
Michael Minella
parent
3a3abdc28a
commit
0f989d9c9f
@@ -6,48 +6,36 @@
|
||||
|
||||
== Scaling and Parallel Processing
|
||||
|
||||
Many batch processing problems can be solved with single threaded,
|
||||
single process jobs, so it is always a good idea to properly check if that
|
||||
meets your needs before thinking about more complex implementations. Measure
|
||||
the performance of a realistic job and see if the simplest implementation
|
||||
meets your needs first. You can read and write a file of several hundred
|
||||
megabytes in well under a minute, even with standard hardware.
|
||||
Many batch processing problems can be solved with single threaded, single process jobs,
|
||||
so it is always a good idea to properly check if that meets your needs before thinking
|
||||
about more complex implementations. Measure the performance of a realistic job and see if
|
||||
the simplest implementation meets your needs first. You can read and write a file of
|
||||
several hundred megabytes in well under a minute, even with standard hardware.
|
||||
|
||||
When you are ready to start implementing a job with some parallel
|
||||
processing, Spring Batch offers a range of options, which are described in
|
||||
this chapter, although some features are covered elsewhere. At a high level,
|
||||
there are two modes of parallel processing:
|
||||
When you are ready to start implementing a job with some parallel processing, Spring
|
||||
Batch offers a range of options, which are described in this chapter, although some
|
||||
features are covered elsewhere. At a high level, there are two modes of parallel
|
||||
processing:
|
||||
|
||||
* Single process, multi-threaded
|
||||
* Multi-process
|
||||
|
||||
These break down into categories as well, as
|
||||
follows:
|
||||
|
||||
These break down into categories as well, as follows:
|
||||
|
||||
* Multi-threaded Step (single process)
|
||||
|
||||
|
||||
* Parallel Steps (single process)
|
||||
|
||||
|
||||
* Remote Chunking of Step (multi process)
|
||||
|
||||
|
||||
* Partitioning a Step (single or multi process)
|
||||
|
||||
First, we review the single-process options. Then we review the
|
||||
multi-process options.
|
||||
First, we review the single-process options. Then we review the multi-process options.
|
||||
|
||||
[[multithreadedStep]]
|
||||
|
||||
|
||||
=== Multi-threaded Step
|
||||
|
||||
The simplest way to start parallel processing is to add a
|
||||
`TaskExecutor` to your Step configuration. For example, you might add an
|
||||
attribute of the `tasklet`, as shown in the following example:
|
||||
|
||||
The simplest way to start parallel processing is to add a `TaskExecutor` to your Step
|
||||
configuration. For example, you might add an attribute of the `tasklet`, as shown in the
|
||||
following example:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
@@ -56,25 +44,21 @@ The simplest way to start parallel processing is to add a
|
||||
</step>
|
||||
----
|
||||
|
||||
In this example, the taskExecutor is a reference to another bean
|
||||
definition that implements the `TaskExecutor`
|
||||
interface. https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/task/TaskExecutor.html[`TaskExecutor`] is a standard Spring
|
||||
interface, so consult the Spring User Guide for details of available
|
||||
implementations. The simplest multi-threaded
|
||||
`TaskExecutor` is a
|
||||
`SimpleAsyncTaskExecutor`.
|
||||
|
||||
The result of the above configuration is that the `Step`
|
||||
executes by reading, processing, and writing each chunk of items
|
||||
(each commit interval) in a separate thread of execution. Note
|
||||
that this means there is no fixed order for the items to be
|
||||
processed, and a chunk might contain items that are
|
||||
non-consecutive compared to the single-threaded case. In addition
|
||||
to any limits placed by the task executor (such as whether it is backed by
|
||||
a thread pool), there is a throttle limit in the tasklet
|
||||
configuration which defaults to 4. You may need to increase this
|
||||
to ensure that a thread pool is fully utilized, as shown in the following example:
|
||||
In this example, the taskExecutor is a reference to another bean definition that
|
||||
implements the `TaskExecutor` interface.
|
||||
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/task/TaskExecutor.html[`TaskExecutor`]
|
||||
is a standard Spring interface, so consult the Spring User Guide for details of available
|
||||
implementations. The simplest multi-threaded `TaskExecutor` is a
|
||||
`SimpleAsyncTaskExecutor`.
|
||||
|
||||
The result of the above configuration is that the `Step` executes by reading, processing,
|
||||
and writing each chunk of items (each commit interval) in a separate thread of execution.
|
||||
Note that this means there is no fixed order for the items to be processed, and a chunk
|
||||
might contain items that are non-consecutive compared to the single-threaded case. In
|
||||
addition to any limits placed by the task executor (such as whether it is backed by a
|
||||
thread pool), there is a throttle limit in the tasklet configuration which defaults to 4.
|
||||
You may need to increase this to ensure that a thread pool is fully utilized, as shown in
|
||||
the following example:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
@@ -84,49 +68,41 @@ The result of the above configuration is that the `Step`
|
||||
</step>
|
||||
----
|
||||
|
||||
Note also that there may be limits placed on concurrency by
|
||||
any pooled resources used in your step, such as
|
||||
a `DataSource`. Be sure to make the pool in
|
||||
those resources at least as large as the desired number of
|
||||
concurrent threads in the step.
|
||||
Note also that there may be limits placed on concurrency by any pooled resources used in
|
||||
your step, such as a `DataSource`. Be sure to make the pool in those resources at least
|
||||
as large as the desired number of concurrent threads in the step.
|
||||
|
||||
There are some practical limitations of using multi-threaded `Step` implementations
|
||||
for some common batch use cases. Many participants in a `Step` (such as readers
|
||||
and writers) are stateful. If the state is not segregated by thread,
|
||||
then those components are not usable in a multi-threaded `Step`. In
|
||||
particular, most of the off-the-shelf readers and writers from Spring Batch
|
||||
are not designed for multi-threaded use. It is, however, possible to work
|
||||
with stateless or thread safe readers and writers, and there is a sample
|
||||
(called `parallelJob`) in the https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples[Spring Batch Samples] that show the use of a process
|
||||
indicator (see <<readersAndWriters.adoc#process-indicator,Preventing State Persistence>>) to keep
|
||||
track of items that have been processed in a database input table.
|
||||
|
||||
Spring Batch provides some implementations of
|
||||
`ItemWriter` and
|
||||
`ItemReader`. Usually, they say in the
|
||||
Javadoc if they are thread safe or not or what you have to do to
|
||||
avoid problems in a concurrent environment. If there is no
|
||||
information in the Javadoc, you can check the implementation to see
|
||||
if there is any state. If a reader is not thread safe, it may
|
||||
still be efficient to use it in your own synchronizing delegator.
|
||||
You can synchronize the call to `read()` and as
|
||||
long as the processing and writing is the most expensive part of
|
||||
the chunk, your step may still complete much faster than it would in a
|
||||
single threaded configuration.
|
||||
There are some practical limitations of using multi-threaded `Step` implementations for
|
||||
some common batch use cases. Many participants in a `Step` (such as readers and writers)
|
||||
are stateful. If the state is not segregated by thread, then those components are not
|
||||
usable in a multi-threaded `Step`. In particular, most of the off-the-shelf readers and
|
||||
writers from Spring Batch are not designed for multi-threaded use. It is, however,
|
||||
possible to work with stateless or thread safe readers and writers, and there is a sample
|
||||
(called `parallelJob`) in the
|
||||
https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples[Spring
|
||||
Batch Samples] that show the use of a process indicator (see
|
||||
<<readersAndWriters.adoc#process-indicator,Preventing State Persistence>>) to keep track
|
||||
of items that have been processed in a database input table.
|
||||
|
||||
Spring Batch provides some implementations of `ItemWriter` and `ItemReader`. Usually,
|
||||
they say in the Javadoc if they are thread safe or not or what you have to do to avoid
|
||||
problems in a concurrent environment. If there is no information in the Javadoc, you can
|
||||
check the implementation to see if there is any state. If a reader is not thread safe,
|
||||
it may still be efficient to use it in your own synchronizing delegator. You can
|
||||
synchronize the call to `read()` and as long as the processing and writing is the most
|
||||
expensive part of the chunk, your step may still complete much faster than it would in a
|
||||
single threaded configuration.
|
||||
|
||||
[[scalabilityParallelSteps]]
|
||||
|
||||
|
||||
=== Parallel Steps
|
||||
|
||||
As long as the application logic that needs to be parallelized can
|
||||
be split into distinct responsibilities and assigned to individual steps,
|
||||
then it can be parallelized in a single process. Parallel Step execution
|
||||
is easy to configure and use, for example, to execute steps
|
||||
`(step1,step2)` in parallel with
|
||||
`step3`, as shown in the following example:
|
||||
|
||||
As long as the application logic that needs to be parallelized can be split into distinct
|
||||
responsibilities and assigned to individual steps, then it can be parallelized in a
|
||||
single process. Parallel Step execution is easy to configure and use, for example, to
|
||||
execute steps `(step1,step2)` in parallel with `step3`, as shown in the following
|
||||
example:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
@@ -146,91 +122,76 @@ As long as the application logic that needs to be parallelized can
|
||||
<beans:bean id="taskExecutor" class="org.spr...SimpleAsyncTaskExecutor"/>
|
||||
----
|
||||
|
||||
The configurable "task-executor" attribute is used to specify which
|
||||
`TaskExecutor` implementation should be used to execute the individual
|
||||
flows. The default is `SyncTaskExecutor`, but an
|
||||
asynchronous `TaskExecutor` is required to run the steps in parallel. Note
|
||||
that the job ensures that every flow in the split completes before
|
||||
aggregating the exit statuses and transitioning.
|
||||
The configurable "task-executor" attribute is used to specify which `TaskExecutor`
|
||||
implementation should be used to execute the individual flows. The default is
|
||||
`SyncTaskExecutor`, but an asynchronous `TaskExecutor` is required to run the steps in
|
||||
parallel. Note that the job ensures that every flow in the split completes before
|
||||
aggregating the exit statuses and transitioning.
|
||||
|
||||
See the section on <<step.adoc#split-flows,Split Flows>> for more
|
||||
detail.
|
||||
See the section on <<step.adoc#split-flows,Split Flows>> for moredetail.
|
||||
|
||||
[[remoteChunking]]
|
||||
|
||||
|
||||
=== Remote Chunking
|
||||
|
||||
In remote chunking, the `Step` processing is split across multiple
|
||||
processes, communicating with each other through some middleware. The following
|
||||
image shows the pattern:
|
||||
In remote chunking, the `Step` processing is split across multiple processes,
|
||||
communicating with each other through some middleware. The following image shows the
|
||||
pattern:
|
||||
|
||||
.Remote Chunking
|
||||
image::{batch-asciidoc}images/remote-chunking.png[Remote Chunking, scaledwidth="60%"]
|
||||
|
||||
The master component is a single process, and the slaves are
|
||||
multiple remote processes. This pattern works best if the master
|
||||
is not a bottleneck, so the processing must be more expensive than the
|
||||
reading of items (as is often the case in practice).
|
||||
The master component is a single process, and the slaves are multiple remote processes.
|
||||
This pattern works best if the master is not a bottleneck, so the processing must be more
|
||||
expensive than the reading of items (as is often the case in practice).
|
||||
|
||||
The master is an implementation of a Spring Batch
|
||||
`Step` with the `ItemWriter` replaced by a generic
|
||||
version that knows how to send chunks of items to the middleware as
|
||||
messages. The slaves are standard listeners for whatever middleware is
|
||||
being used (for example, with JMS, they would be
|
||||
`MesssageListener` implementations), and their role is to process
|
||||
the chunks of items using a standard `ItemWriter` or
|
||||
`ItemProcessor` plus
|
||||
`ItemWriter`, through the
|
||||
`ChunkProcessor` interface. One of the advantages of
|
||||
using this pattern is that the reader, processor, and writer components are
|
||||
off-the-shelf (the same as would be used for a local execution of the
|
||||
step). The items are divided up dynamically and work is shared through the
|
||||
middleware, so that, if the listeners are all eager consumers, then load
|
||||
balancing is automatic.
|
||||
The master is an implementation of a Spring Batch `Step` with the `ItemWriter` replaced
|
||||
by a generic version that knows how to send chunks of items to the middleware as
|
||||
messages. The slaves are standard listeners for whatever middleware is being used (for
|
||||
example, with JMS, they would be `MesssageListener` implementations), and their role is
|
||||
to process the chunks of items using a standard `ItemWriter` or `ItemProcessor` plus
|
||||
`ItemWriter`, through the `ChunkProcessor` interface. One of the advantages of using this
|
||||
pattern is that the reader, processor, and writer components are off-the-shelf (the same
|
||||
as would be used for a local execution of the step). The items are divided up dynamically
|
||||
and work is shared through the middleware, so that, if the listeners are all eager
|
||||
consumers, then load balancing is automatic.
|
||||
|
||||
The middleware has to be durable, with guaranteed delivery and a
|
||||
single consumer for each message. JMS is the obvious candidate, but other
|
||||
options (such as Java Spaces exist in the grid computing and shared memory product space.
|
||||
The middleware has to be durable, with guaranteed delivery and a single consumer for each
|
||||
message. JMS is the obvious candidate, but other options (such as Java Spaces exist in
|
||||
the grid computing and shared memory product space.
|
||||
|
||||
[[partitioning]]
|
||||
|
||||
|
||||
=== Partitioning
|
||||
|
||||
Spring Batch also provides an SPI for partitioning a `Step` execution
|
||||
and executing it remotely. In this case, the remote participants are
|
||||
`Step` instances that could just as easily have been configured and used for
|
||||
local processing. The following image shows the pattern:
|
||||
Spring Batch also provides an SPI for partitioning a `Step` execution and executing it
|
||||
remotely. In this case, the remote participants are `Step` instances that could just as
|
||||
easily have been configured and used for local processing. The following image shows the
|
||||
pattern:
|
||||
|
||||
.Partitioning
|
||||
image::{batch-asciidoc}images/partitioning-overview.png[Partitioning Overview, scaledwidth="60%"]
|
||||
|
||||
The `Job` runs on the left-hand side as a sequence of `Step` instances,
|
||||
and one of the `Step` instances is labeled as a master. The slaves in this picture
|
||||
are all identical instances of a `Step`, which could in fact take the place
|
||||
of the master, resulting in the same outcome for the `Job`. The slaves are
|
||||
typically going to be remote services but could also be local threads of
|
||||
execution. The messages sent by the master to the slaves in this pattern
|
||||
do not need to be durable or have guaranteed delivery. Spring Batch
|
||||
metadata in the JobRepository ensures that
|
||||
each slave is executed once and only once for each `Job` execution.
|
||||
The `Job` runs on the left-hand side as a sequence of `Step` instances, and one of the
|
||||
`Step` instances is labeled as a master. The slaves in this picture are all identical
|
||||
instances of a `Step`, which could in fact take the place of the master, resulting in the
|
||||
same outcome for the `Job`. The slaves are typically going to be remote services but
|
||||
could also be local threads of execution. The messages sent by the master to the slaves
|
||||
in this pattern do not need to be durable or have guaranteed delivery. Spring Batch
|
||||
metadata in the JobRepository ensures that each slave is executed once and only once for
|
||||
each `Job` execution.
|
||||
|
||||
The SPI in Spring Batch consists of a special implementation of `Step`
|
||||
(called the `PartitionStep`) and two strategy interfaces
|
||||
that need to be implemented for the specific environment. The strategy
|
||||
interfaces are `PartitionHandler` and
|
||||
`StepExecutionSplitter`, and their role is shown in
|
||||
the following sequence diagram:
|
||||
The SPI in Spring Batch consists of a special implementation of `Step` (called the
|
||||
`PartitionStep`) and two strategy interfaces that need to be implemented for the specific
|
||||
environment. The strategy interfaces are `PartitionHandler` and `StepExecutionSplitter`,
|
||||
and their role is shown in the following sequence diagram:
|
||||
|
||||
.Partitioning SPI
|
||||
image::{batch-asciidoc}images/partitioning-spi.png[Partitioning SPI, scaledwidth="60%"]
|
||||
|
||||
The `Step` on the right in this case is the "remote" slave, so,
|
||||
potentially, there are many objects and or processes playing this role, and
|
||||
the `PartitionStep` is shown driving the execution. The following example shows the `PartitionStep`
|
||||
configuration:
|
||||
|
||||
The `Step` on the right in this case is the "remote" slave, so, potentially, there are
|
||||
many objects and or processes playing this role, and the `PartitionStep` is shown driving
|
||||
the execution. The following example shows the `PartitionStep` configuration:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
@@ -241,53 +202,44 @@ The `Step` on the right in this case is the "remote" slave, so,
|
||||
</step>
|
||||
----
|
||||
|
||||
Similar to the multi-threaded step's `throttle-limit`
|
||||
attribute, the `grid-size` attribute prevents the task executor from
|
||||
being saturated with requests from a single step.
|
||||
Similar to the multi-threaded step's `throttle-limit` attribute, the `grid-size`
|
||||
attribute prevents the task executor from being saturated with requests from a single
|
||||
step.
|
||||
|
||||
There is a simple example that can be copied and extended in the
|
||||
unit test suite for https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples/src/main/resources/jobs[Spring Batch Samples] (see
|
||||
`Partition*Job.xml` configuration).
|
||||
There is a simple example that can be copied and extended in the unit test suite for
|
||||
https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples/src/main/resources/jobs[Spring
|
||||
Batch Samples] (see `Partition*Job.xml` configuration).
|
||||
|
||||
Spring Batch creates step executions for the partitions called
|
||||
"step1:partition0", and so on. Many people prefer to call the master step
|
||||
"step1:master" for consistency. You can use an
|
||||
alias for the step (by specifying the `name` attribute
|
||||
instead of the `id` attribute).
|
||||
Spring Batch creates step executions for the partitions called "step1:partition0", and so
|
||||
on. Many people prefer to call the master step "step1:master" for consistency. You can
|
||||
use an alias for the step (by specifying the `name` attribute instead of the `id`
|
||||
attribute).
|
||||
|
||||
[[partitionHandler]]
|
||||
|
||||
|
||||
==== PartitionHandler
|
||||
|
||||
The `PartitionHandler` is the component that
|
||||
knows about the fabric of the remoting or grid environment. It is able
|
||||
to send `StepExecution` requests to the remote
|
||||
`Step` instances, wrapped in some fabric-specific format, like a DTO. It does not
|
||||
have to know how to split the input data or how to aggregate the
|
||||
result of multiple `Step` executions. Generally speaking, it probably also
|
||||
does not need to know about resilience or failover, since those are
|
||||
features of the fabric in many cases. In any case, Spring Batch always
|
||||
provides restartability independent of the fabric. A failed `Job` can
|
||||
always be restarted and only the failed `Steps` are
|
||||
re-executed.
|
||||
The `PartitionHandler` is the component that knows about the fabric of the remoting or
|
||||
grid environment. It is able to send `StepExecution` requests to the remote `Step`
|
||||
instances, wrapped in some fabric-specific format, like a DTO. It does not have to know
|
||||
how to split the input data or how to aggregate the result of multiple `Step` executions.
|
||||
Generally speaking, it probably also does not need to know about resilience or failover,
|
||||
since those are features of the fabric in many cases. In any case, Spring Batch always
|
||||
provides restartability independent of the fabric. A failed `Job` can always be restarted
|
||||
and only the failed `Steps` are re-executed.
|
||||
|
||||
The `PartitionHandler` interface can have
|
||||
specialized implementations for a variety of fabric types, including simple
|
||||
RMI remoting, EJB remoting, custom web service, JMS, Java Spaces, shared
|
||||
memory grids (like Terracotta or Coherence), and grid execution fabrics
|
||||
(like GridGain). Spring Batch does not contain implementations for any
|
||||
proprietary grid or remoting fabrics.
|
||||
|
||||
Spring Batch does, however, provide a useful implementation of
|
||||
`PartitionHandler` that executes `Step` instances locally in
|
||||
separate threads of execution, using the
|
||||
`TaskExecutor` strategy from Spring. The
|
||||
implementation is called
|
||||
`TaskExecutorPartitionHandler`, and it is the
|
||||
default for a step configured with the XML namespace shown previously. It can
|
||||
also be configured explicitly, as shown in the following example:
|
||||
The `PartitionHandler` interface can have specialized implementations for a variety of
|
||||
fabric types, including simple RMI remoting, EJB remoting, custom web service, JMS, Java
|
||||
Spaces, shared memory grids (like Terracotta or Coherence), and grid execution fabrics
|
||||
(like GridGain). Spring Batch does not contain implementations for any proprietary grid
|
||||
or remoting fabrics.
|
||||
|
||||
Spring Batch does, however, provide a useful implementation of `PartitionHandler` that
|
||||
executes `Step` instances locally in separate threads of execution, using the
|
||||
`TaskExecutor` strategy from Spring. The implementation is called
|
||||
`TaskExecutorPartitionHandler`, and it is the default for a step configured with the XML
|
||||
namespace shown previously. It can also be configured explicitly, as shown in the
|
||||
following example:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
@@ -302,27 +254,23 @@ Spring Batch does, however, provide a useful implementation of
|
||||
</bean>
|
||||
----
|
||||
|
||||
The `gridSize` attribute determines the number of separate
|
||||
step executions to create, so it can be matched to the size of the
|
||||
thread pool in the `TaskExecutor`. Alternatively, it can
|
||||
be set to be larger than the number of threads available, which makes
|
||||
the blocks of work smaller.
|
||||
The `gridSize` attribute determines the number of separate step executions to create, so
|
||||
it can be matched to the size of the thread pool in the `TaskExecutor`. Alternatively, it
|
||||
can be set to be larger than the number of threads available, which makes the blocks of
|
||||
work smaller.
|
||||
|
||||
The `TaskExecutorPartitionHandler` is
|
||||
useful for IO-intensive `Step` instances, such as copying large numbers of files or
|
||||
replicating filesystems into content management systems. It can also be
|
||||
used for remote execution by providing a `Step` implementation that is a
|
||||
proxy for a remote invocation (such as using Spring Remoting).
|
||||
The `TaskExecutorPartitionHandler` is useful for IO-intensive `Step` instances, such as
|
||||
copying large numbers of files or replicating filesystems into content management
|
||||
systems. It can also be used for remote execution by providing a `Step` implementation
|
||||
that is a proxy for a remote invocation (such as using Spring Remoting).
|
||||
|
||||
[[stepExecutionSplitter]]
|
||||
|
||||
|
||||
==== Partitioner
|
||||
|
||||
The `Partitioner` has a simpler responsibility: to generate
|
||||
execution contexts as input parameters for new step executions only (no
|
||||
need to worry about restarts). It has a single method, as shown in the following interface definition:
|
||||
|
||||
The `Partitioner` has a simpler responsibility: to generate execution contexts as input
|
||||
parameters for new step executions only (no need to worry about restarts). It has a
|
||||
single method, as shown in the following interface definition:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@@ -331,57 +279,40 @@ public interface Partitioner {
|
||||
}
|
||||
----
|
||||
|
||||
The return value from this method associates a unique name for
|
||||
each step execution (the `String`) with input
|
||||
parameters in the form of an `ExecutionContext`.
|
||||
The names show up later in the Batch metadata as the step name in the
|
||||
partitioned `StepExecutions`. The
|
||||
`ExecutionContext` is just a bag of name-value
|
||||
pairs, so it might contain a range of primary keys, line numbers, or
|
||||
the location of an input file. The remote `Step`
|
||||
then normally binds to the context input using `#{...}`
|
||||
placeholders (late binding in step scope), as illustrated in the next
|
||||
section.
|
||||
The return value from this method associates a unique name for each step execution (the
|
||||
`String`) with input parameters in the form of an `ExecutionContext`. The names show up
|
||||
later in the Batch metadata as the step name in the partitioned `StepExecutions`. The
|
||||
`ExecutionContext` is just a bag of name-value pairs, so it might contain a range of
|
||||
primary keys, line numbers, or the location of an input file. The remote `Step` then
|
||||
normally binds to the context input using `#{...}` placeholders (late binding in step
|
||||
scope), as illustrated in the next section.
|
||||
|
||||
The names of the step executions (the keys in the
|
||||
`Map` returned by
|
||||
`Partitioner`) need to be unique amongst the step
|
||||
executions of a `Job` but do not have any other specific requirements.
|
||||
The easiest way to do this (and to make the names meaningful for users)
|
||||
is to use a prefix+suffix naming convention, where the prefix is the
|
||||
name of the step that is being executed (which itself is unique in the
|
||||
`Job`), and the suffix is just a counter. There is
|
||||
a `SimplePartitioner` in the framework that uses
|
||||
this convention.
|
||||
The names of the step executions (the keys in the `Map` returned by `Partitioner`) need
|
||||
to be unique amongst the step executions of a `Job` but do not have any other specific
|
||||
requirements. The easiest way to do this (and to make the names meaningful for users) is
|
||||
to use a prefix+suffix naming convention, where the prefix is the name of the step that
|
||||
is being executed (which itself is unique in the `Job`), and the suffix is just a
|
||||
counter. There is a `SimplePartitioner` in the framework that uses this convention.
|
||||
|
||||
An optional interface called
|
||||
`PartitionNameProvider` can be used to
|
||||
provide the partition names separately from the partitions
|
||||
themselves. If a `Partitioner` implements
|
||||
this interface, then, on a restart, only the names are queried.
|
||||
If partitioning is expensive, this can be a useful optimization.
|
||||
The names provided by the
|
||||
`PartitionNameProvider` must match those
|
||||
provided by the `Partitioner`.
|
||||
An optional interface called `PartitionNameProvider` can be used to provide the partition
|
||||
names separately from the partitions themselves. If a `Partitioner` implements this
|
||||
interface, then, on a restart, only the names are queried. If partitioning is expensive,
|
||||
this can be a useful optimization. The names provided by the `PartitionNameProvider` must
|
||||
match those provided by the `Partitioner`.
|
||||
|
||||
[[bindingInputDataToSteps]]
|
||||
|
||||
|
||||
==== Binding Input Data to Steps
|
||||
|
||||
It is very efficient for the steps that are executed by the
|
||||
`PartitionHandler` to have identical configuration and for their input
|
||||
parameters to be bound at runtime from the `ExecutionContext`. This is
|
||||
easy to do with the StepScope feature of Spring Batch (covered in more
|
||||
detail in the section on <<step.adoc#late-binding,Late Binding>>). For example,
|
||||
if the `Partitioner` creates
|
||||
`ExecutionContext` instances with an attribute key called
|
||||
`fileName`, pointing to a different file (or
|
||||
directory) for each step invocation, the
|
||||
`Partitioner` output might resemble the content of the following table:
|
||||
It is very efficient for the steps that are executed by the `PartitionHandler` to have
|
||||
identical configuration and for their input parameters to be bound at runtime from the
|
||||
`ExecutionContext`. This is easy to do with the StepScope feature of Spring Batch
|
||||
(covered in more detail in the section on <<step.adoc#late-binding,Late Binding>>). For
|
||||
example, if the `Partitioner` creates `ExecutionContext` instances with an attribute key
|
||||
called `fileName`, pointing to a different file (or directory) for each step invocation,
|
||||
the `Partitioner` output might resemble the content of the following table:
|
||||
|
||||
.Example step execution name to execution context provided by `Partitioner` targeting directory processing
|
||||
|
||||
|===============
|
||||
|__Step Execution Name (key)__|__ExecutionContext (value)__
|
||||
|filecopy:partition0|fileName=/home/data/one
|
||||
@@ -389,10 +320,8 @@ It is very efficient for the steps that are executed by the
|
||||
|filecopy:partition2|fileName=/home/data/three
|
||||
|===============
|
||||
|
||||
|
||||
Then the file name can be bound to a step using late binding to
|
||||
the execution context, as shown in the following example:
|
||||
|
||||
Then the file name can be bound to a step using late binding to the execution context, as
|
||||
shown in the following example:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
|
||||
Reference in New Issue
Block a user