BATCH-1056: minor fixes
This commit is contained in:
@@ -8,38 +8,39 @@
|
||||
<title>RepeatTemplate</title>
|
||||
|
||||
<para>Batch processing is about repetitive actions - either as a simple
|
||||
optimisation, or as part of a job. To strategie and generalise the
|
||||
repetition, and provide what amounts to an iterator framework, Spring
|
||||
Batch has the <classname>RepeatOperations</classname> interface. The
|
||||
<classname>RepeatOperations</classname> interface looks like this:</para>
|
||||
optimisation, or as part of a job. To strategize and generalize the
|
||||
repetition as well as to provide what amounts to an iterator framework,
|
||||
Spring Batch has the <classname>RepeatOperations</classname> interface.
|
||||
The <classname>RepeatOperations</classname> interface looks like
|
||||
this:</para>
|
||||
|
||||
<para><programlisting>public interface RepeatOperations {
|
||||
|
||||
ExitStatus iterate(RepeatCallback callback) throws RepeatException;
|
||||
RepeatStatus iterate(RepeatCallback callback) throws RepeatException;
|
||||
|
||||
}</programlisting>where the callback is a simple interface that allows you to
|
||||
insert some business logic to be repeated</para>
|
||||
}</programlisting>The callback is a simple interface that allows you to insert
|
||||
some business logic to be repeated:</para>
|
||||
|
||||
<para><programlisting>public interface RepeatCallback {
|
||||
|
||||
ExitStatus doInIteration(RepeatContext context) throws Exception;
|
||||
RepeatStatus doInIteration(RepeatContext context) throws Exception;
|
||||
|
||||
}</programlisting>The callback is executed repeatedly, until the
|
||||
implementation decides that the iteration should end. The return value in
|
||||
these interfaces is a special form of extendable enumeration (not a true
|
||||
enumeration because users are free to create new values). An
|
||||
<classname>ExitStatus</classname> is immutable and conveys information to
|
||||
the caller of the repeat operations about whether there is any more work
|
||||
to do. Generally speaking, implementations of
|
||||
}</programlisting>The callback is executed repeatedly until the implementation
|
||||
decides that the iteration should end. The return value in these
|
||||
interfaces is an enumeration that can either be
|
||||
<code>RepeatStatus.CONTINUABLE</code> or
|
||||
<code>RepeatStatus.FINISHED</code>. A <classname>RepeatStatus</classname>
|
||||
conveys information to the caller of the repeat operations about whether
|
||||
there is any more work to do. Generally speaking, implementations of
|
||||
<classname>RepeatOperations</classname> should inspect the
|
||||
<classname>ExitStatus</classname> and use it as part of the decision to
|
||||
<classname>RepeatStatus</classname> and use it as part of the decision to
|
||||
end the iteration. Any callback that wishes to signal to the caller that
|
||||
there is no more work to do can return
|
||||
<code>ExitStatus.FINISHED</code>.</para>
|
||||
<code>RepeatStatus.FINISHED</code>.</para>
|
||||
|
||||
<para>The simplest general purpose implementation of
|
||||
<classname>RepeatOperations</classname> is
|
||||
<classname>RepeatTemplate</classname>. It could be used like this</para>
|
||||
<classname>RepeatTemplate</classname>. It could be used like this:</para>
|
||||
|
||||
<programlisting>RepeatTemplate template = new RepeatTemplate();
|
||||
|
||||
@@ -54,13 +55,13 @@ template.iterate(new RepeatCallback() {
|
||||
|
||||
});</programlisting>
|
||||
|
||||
<para>In the example we return <code>ExitStatus.CONTINUABLE</code> to show
|
||||
that there is more work to do. The callback can also return
|
||||
<para>In the example we return <code>RepeatStatus.CONTINUABLE</code> to
|
||||
show that there is more work to do. The callback can also return
|
||||
<code>ExitStatus.FINISHED</code> if it wants to signal to the caller that
|
||||
there is no more work to do. Some iterations can be terminated by
|
||||
considerations intrinsic to the work being done in the callback, others
|
||||
are effectively infinite loops as far as the callback is concerned, and
|
||||
the completion decision is delegated to an external policy as in the case
|
||||
are effectively infinite loops as far as the callback is concerned and the
|
||||
completion decision is delegated to an external policy as in the case
|
||||
above.</para>
|
||||
|
||||
<section>
|
||||
@@ -82,77 +83,44 @@ template.iterate(new RepeatCallback() {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>ExitStatus</title>
|
||||
<title>RepeatStatus</title>
|
||||
|
||||
<para><classname>ExitStatus</classname> is used by Spring Batch to
|
||||
indicate whether processing has finished, and if so whether or not is
|
||||
was successful. It is also used to carry textual information about the
|
||||
end state of a batch or iteration, in the form of an exit code and a
|
||||
description of the status in freeform text. These are the properties of
|
||||
an <classname>ExitStatus</classname>:</para>
|
||||
<para><classname>RepeatStatus</classname> is an enumeration used by
|
||||
Spring Batch to indicate whether processing has finished. These are
|
||||
possible <classname>RepeatStatus</classname> values:</para>
|
||||
|
||||
<table>
|
||||
<title>ExitStatus properties</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Property Name</entry>
|
||||
<entry><emphasis role="bold">Value</emphasis></entry>
|
||||
|
||||
<entry>Type</entry>
|
||||
|
||||
<entry>Description</entry>
|
||||
<entry><emphasis role="bold">Description</emphasis></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>continuable</entry>
|
||||
<entry>CONTINUABLE</entry>
|
||||
|
||||
<entry>boolean</entry>
|
||||
|
||||
<entry>true if there is more work to do</entry>
|
||||
<entry>There is more work to do.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>exitCode</entry>
|
||||
<entry>FINISHED</entry>
|
||||
|
||||
<entry>String</entry>
|
||||
|
||||
<entry>Short code describing the exit status, e.g. CONTINUABLE,
|
||||
FINISHED, FAILED</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>exitDescription</entry>
|
||||
|
||||
<entry>String</entry>
|
||||
|
||||
<entry>Long description of the exit status, could be a stack
|
||||
trace for example.</entry>
|
||||
<entry>No more repetitions should take place.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para><classname>ExitStatus</classname> values are designed to be
|
||||
flexible, so that they can be created with any code and description the
|
||||
user needs. Spring Batch comes with some standard values out of the box,
|
||||
to support common use cases, but users are free to create their own
|
||||
values, as long as the semantics of the <code>continuable</code>
|
||||
property are honoured.</para>
|
||||
|
||||
<para>ExitStatus values can also be combined with various operators
|
||||
built into the class as methods. You can add an exit code, or
|
||||
description, or combine the continuable values with logical AND using
|
||||
methods in ExitStatus. You can also combine two ExitStatus values with
|
||||
the and method taking ExitStatus as a parameter. The effect of this is
|
||||
to do a logical AND on the continuable flag, concatenate the
|
||||
descriptions and replace the exit code with the new value, as long as
|
||||
the result is continuable, or the input is not continuable. This has the
|
||||
effect of maintaining the semantics of the continuable flag, but not
|
||||
making any "surprising" changes to the exit code (e.g. it never becomes
|
||||
CONTINUABLE when it was already FINISHED, unless someone does something
|
||||
wilful, like pass in a value that is not continuable, but with a code of
|
||||
CONTINUABLE).</para>
|
||||
<para><classname>RepeatStatus</classname> values can also be combined
|
||||
with a logical AND operation using the <methodname>and</methodname>()
|
||||
method in <classname>RepeatStatus</classname>. The effect of this is to
|
||||
do a logical AND on the continuable flag. In other words, if either
|
||||
status is <code>FINISHED</code>, then the result will be
|
||||
<code>FINISHED</code>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -167,22 +135,22 @@ template.iterate(new RepeatCallback() {
|
||||
current policy to create a <classname>RepeatContext</classname> and pass
|
||||
that in to the <classname>RepeatCallback</classname> at every stage in the
|
||||
iteration. After a callback completes its
|
||||
<methodname>doInIteration</methodname> the
|
||||
<methodname>doInIteration</methodname>, the
|
||||
<classname>RepeatTemplate</classname> has to make a call to the
|
||||
<classname>CompletionPolicy</classname> to ask it to update its state
|
||||
(which will be stored in the <classname>RepeatContext</classname>), then
|
||||
(which will be stored in the <classname>RepeatContext</classname>). Then
|
||||
it asks the policy if the iteration is complete.</para>
|
||||
|
||||
<para>Spring Batch provides some simple general purpose implementations of
|
||||
<classname>CompletionPolicy</classname>, for example the
|
||||
<classname>SimpleCompletionPolicy</classname> used in the example above.
|
||||
The <classname>SimpleCompletionPolicy</classname> just allows an execution
|
||||
up to a fixed number of times (with <code>ExitStatus.FINISHED</code>
|
||||
<classname>CompletionPolicy</classname>. The
|
||||
<classname>SimpleCompletionPolicy</classname> just allows an execution up
|
||||
to a fixed number of times (with <code>RepeatStatus.FINISHED</code>
|
||||
forcing early completion at any time).</para>
|
||||
|
||||
<para>Users might need to implement their own completion policies for more
|
||||
complicated decisions, e.g. a batch processing window that prevents batch
|
||||
jobs from executing once the online systems are in use.</para>
|
||||
complicated decisions. For example, a batch processing window that
|
||||
prevents batch jobs from executing once the online systems are in use
|
||||
would require a custom policy.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -227,7 +195,7 @@ template.iterate(new RepeatCallback() {
|
||||
interface. The <classname>RepeatTemplate</classname> allows users to
|
||||
register <classname>RepeatListener</classname>s, and they will be given
|
||||
callbacks with the <classname>RepeatContext</classname> and
|
||||
<classname>ExitStatus</classname> where available during the
|
||||
<classname>RepeatStatus</classname> where available during the
|
||||
iteration.</para>
|
||||
|
||||
<para>The interface looks like this:</para>
|
||||
@@ -235,7 +203,7 @@ template.iterate(new RepeatCallback() {
|
||||
<para><programlisting>public interface RepeatListener {
|
||||
void before(RepeatContext context);
|
||||
|
||||
void after(RepeatContext context, ExitStatus result);
|
||||
void after(RepeatContext context, RepeatStatus result);
|
||||
|
||||
void open(RepeatContext context);
|
||||
|
||||
@@ -245,13 +213,13 @@ template.iterate(new RepeatCallback() {
|
||||
}
|
||||
</programlisting>The <methodname>open</methodname> and
|
||||
<methodname>close</methodname> callbacks come before and after the entire
|
||||
iteration, and <methodname>before</methodname>,
|
||||
<methodname>after</methodname> and <methodname>onError</methodname> apply
|
||||
to the individual RepeatCallback calls.</para>
|
||||
iteration. <methodname>before</methodname>, <methodname>after</methodname>
|
||||
and <methodname>onError</methodname> apply to the individual
|
||||
RepeatCallback calls.</para>
|
||||
|
||||
<para>Note that when there is more than one listener, they are in a list,
|
||||
so there is an order. In this case <methodname>open</methodname> and
|
||||
<methodname>before</methodname> are called in the same order, and
|
||||
<methodname>before</methodname> are called in the same order while
|
||||
<methodname>after</methodname>, <methodname>onError</methodname> and
|
||||
<methodname>close</methodname> are called in reverse order.</para>
|
||||
</section>
|
||||
@@ -262,7 +230,7 @@ template.iterate(new RepeatCallback() {
|
||||
<para>Implementations of <classname>RepeatOperations</classname> are not
|
||||
restricted to executing the callback sequentially. It is quite important
|
||||
that some implementations are able to execute their callbacks in parallel.
|
||||
To this end Spring Batch provides the
|
||||
To this end, Spring Batch provides the
|
||||
<classname>TaskExecutorRepeatTemplate</classname>, which uses the Spring
|
||||
<classname>TaskExecutor</classname> strategy to run the
|
||||
<classname>RepeatCallback</classname>. The default is to use a
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
<para>To make processing more robust and less prone to failure, sometimes
|
||||
it helps to automatically retry a failed operation in case it might
|
||||
succeed on a subsequent attempt. Errors that are susceptible to this kind
|
||||
of treatment are transient in nature, for example a remote call to a web
|
||||
service or RMI service that fails because of a network glitch, or a
|
||||
<classname>DeadLockLoserException</classname> in a database update. To
|
||||
automate the retry of such operations Spring Batch has the
|
||||
<classname>RetryOperations</classname> strategy. The
|
||||
<classname>RetryOperations</classname> interface looks like this:</para>
|
||||
of treatment are transient in nature. For example a remote call to a web
|
||||
service or RMI service that fails because of a network glitch or a
|
||||
<classname>DeadLockLoserException</classname> in a database update may
|
||||
resolve themselves after a short wait. To automate the retry of such
|
||||
operations Spring Batch has the <classname>RetryOperations</classname>
|
||||
strategy. The <classname>RetryOperations</classname> interface looks like
|
||||
this:</para>
|
||||
|
||||
<para><programlisting>public interface RetryOperations {
|
||||
|
||||
@@ -30,8 +31,8 @@
|
||||
<T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback,
|
||||
RetryState retryState) throws Exception;
|
||||
|
||||
}</programlisting>where the basic callback is a simple interface that allows
|
||||
you to insert some business logic to be retried</para>
|
||||
}</programlisting>The basic callback is a simple interface that allows you to
|
||||
insert some business logic to be retried:</para>
|
||||
|
||||
<para><programlisting>public interface RetryCallback<T> {
|
||||
|
||||
@@ -86,9 +87,9 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
|
||||
<para>When a retry is exhausted the
|
||||
<classname>RetryOperations</classname> can pass control to a different
|
||||
callback, the <classname>RetryCallback</classname>. To use this feature
|
||||
clients just pass in the callbacks together to the same method, for
|
||||
example:</para>
|
||||
callback, the <classname>RecoveryCallback</classname>. To use this
|
||||
feature clients just pass in the callbacks together to the same method,
|
||||
for example:</para>
|
||||
|
||||
<para><programlisting>Foo foo = template.execute(new RetryCallback<Foo>() {
|
||||
public Foo doWithRetry(RetryContext context) {
|
||||
@@ -106,7 +107,7 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
<section>
|
||||
<title>Stateless Retry</title>
|
||||
|
||||
<para>In the simplest case a retry is just a while loop - the
|
||||
<para>In the simplest case, a retry is just a while loop: the
|
||||
<classname>RetryTemplate</classname> can just keep trying until it
|
||||
either succeeds or fails. The <classname>RetryContext</classname>
|
||||
contains some state to determine whether to retry or abort, but this
|
||||
@@ -123,12 +124,12 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
<title>Stateful Retry</title>
|
||||
|
||||
<para>Where the failure has caused a transactional resource to become
|
||||
invalid there are some special considerations. This does not apply to a
|
||||
simple remote call because there was no transactional resource
|
||||
(usually), but it does sometimes apply to a database update, especially
|
||||
when using Hibernate. In this case it only makes sense to rethrow the
|
||||
exception that called the failure immediately, so that the transaction
|
||||
can roll back, and we can start a new valid one.</para>
|
||||
invalid, there are some special considerations. This does not apply to a
|
||||
simple remote call because there is no transactional resource (usually),
|
||||
but it does sometimes apply to a database update, especially when using
|
||||
Hibernate. In this case it only makes sense to rethrow the exception
|
||||
that called the failure immediately so that the transaction can roll
|
||||
back and we can start a new valid one.</para>
|
||||
|
||||
<para>In these cases a stateless retry is not good enough because the
|
||||
re-throw and roll back necessarily involve leaving the
|
||||
@@ -142,20 +143,21 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
<classname>Map</classname>. Advanced usage with multiple processes in a
|
||||
clustered environment might also consider implementing the
|
||||
<classname>RetryContextCache</classname> with a cluster cache of some
|
||||
sort (even in a clustered environment this might be overkill).</para>
|
||||
sort (though, even in a clustered environment this might be
|
||||
overkill).</para>
|
||||
|
||||
<para>Part of the responsibility of the
|
||||
<classname>RetryOperations</classname> is to recognise the failed
|
||||
<classname>RetryOperations</classname> is to recognize the failed
|
||||
operations when they come back in a new execution (and usually wrapped
|
||||
in a new transaction). To facilitate this, Spring Batch provides the
|
||||
<classname>RetryState</classname> abstraction. This works in conjunction
|
||||
with a special <classname>execute</classname> methods in the
|
||||
<classname>RetryOperations</classname>.</para>
|
||||
|
||||
<para>The way the failed operations are recognised is by identifying the
|
||||
state across multiple invocations of the retry. To identify the state
|
||||
the user can provide an <classname>RetryState</classname> object, and
|
||||
this is responsible for returning a unique key identifying the item. The
|
||||
<para>The way the failed operations are recognized is by identifying the
|
||||
state across multiple invocations of the retry. To identify the state,
|
||||
the user can provide an <classname>RetryState</classname> object that is
|
||||
responsible for returning a unique key identifying the item. The
|
||||
identifier is used as a key in the
|
||||
<classname>RetryContextCache</classname>.</para>
|
||||
|
||||
@@ -176,9 +178,8 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
<classname>RetryOperations</classname>.</para>
|
||||
|
||||
<para>The decision to retry or not is actually delegated to a regular
|
||||
retry policy, so the usual concerns about limits and timeouts can be
|
||||
injected through the <classname>RetryPolicy</classname> (see
|
||||
below).</para>
|
||||
<classname>RetryPolicy</classname>, so the usual concerns about limits
|
||||
and timeouts can be injected there (see below).</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -199,8 +200,8 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
another attempt can be made. If another attempt cannot be made (e.g. a
|
||||
limit is reached or a timeout is detected) then the policy is also
|
||||
responsible for handling the exhausted state. Simple implementations will
|
||||
just throw <classname>RetryExhaustedException</classname>, and any
|
||||
enclosing transaction will be rolled back. More sophisticated
|
||||
just throw <classname>RetryExhaustedException</classname> which will cause
|
||||
any enclosing transaction to be rolled back. More sophisticated
|
||||
implementations might attempt to take some recovery action, in which case
|
||||
the transaction can remain intact.</para>
|
||||
|
||||
@@ -210,9 +211,8 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
doesn't help to retry it. So don't retry on all exception types - try to
|
||||
focus on only those exceptions that you expect to be retryable. It's not
|
||||
usually harmful to the business logic to retry more aggressively, but
|
||||
it's wasteful because if a failure is deterministic there could be a
|
||||
very tight loop retrying something that you know in advance is
|
||||
fatal.</para>
|
||||
it's wasteful because if a failure is deterministic there will be time
|
||||
spent retrying something that you know in advance is fatal.</para>
|
||||
</tip>
|
||||
|
||||
<para>Spring Batch provides some simple general purpose implementations of
|
||||
@@ -224,8 +224,8 @@ Foo result = template.execute(new RetryCallback<Foo>() {
|
||||
<para>The <classname>SimpleRetryPolicy</classname> just allows a retry on
|
||||
any of a named list of exception types, up to a fixed number of times. It
|
||||
also has a list of "fatal" exceptions that should never be retried, and
|
||||
this list overrides the retryable list, so it can be used to give finer
|
||||
control over the retry behaviour, e.g.</para>
|
||||
this list overrides the retryable list so that it can be used to give
|
||||
finer control over the retry behavior:</para>
|
||||
|
||||
<programlisting>SimpleRetryPolicy policy = new SimpleRetryPolicy(5);
|
||||
// Retry on all exceptions (this is the default)
|
||||
@@ -244,7 +244,7 @@ template.execute(new RetryCallback<Foo>() {
|
||||
|
||||
<para>There is also a more flexible implementation called
|
||||
<classname>ExceptionClassifierRetryPolicy</classname>, which allows the
|
||||
user to configure different retry behaviour for an arbitrary set of
|
||||
user to configure different retry behavior for an arbitrary set of
|
||||
excecption types though the <classname>ExceptionClassifier</classname>
|
||||
abstraction. The policy works by calling on the classifier to convert an
|
||||
exception into a delegate <classname>RetryPolicy</classname>, so for
|
||||
@@ -252,8 +252,9 @@ template.execute(new RetryCallback<Foo>() {
|
||||
another by mapping it to a different policy.</para>
|
||||
|
||||
<para>Users might need to implement their own retry policies for more
|
||||
customized decisions, e.g. if there is a well-known solution-specific
|
||||
classification of exceptions into retryable and not retryable.</para>
|
||||
customized decisions. For instance, if there is a well-known,
|
||||
solution-specific, classification of exceptions into retryable and not
|
||||
retryable.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -306,16 +307,16 @@ template.execute(new RetryCallback<Foo>() {
|
||||
}
|
||||
</programlisting>The <methodname>open</methodname> and
|
||||
<methodname>close</methodname> callbacks come before and after the entire
|
||||
retry in the simplest case, and <methodname>onError</methodname> applies
|
||||
to the individual RetryCallback calls. The <methodname>close</methodname>
|
||||
method might also receive a <classname>Throwable</classname>, if there has
|
||||
been an error it is the last one thrown by the
|
||||
<classname>RetryCallback</classname>.</para>
|
||||
retry in the simplest case and <methodname>onError</methodname> applies to
|
||||
the individual <classname>RetryCallback</classname> calls. The
|
||||
<methodname>close</methodname> method might also receive a
|
||||
<classname>Throwable</classname>; if there has been an error it is the
|
||||
last one thrown by the <classname>RetryCallback</classname>.</para>
|
||||
|
||||
<para>Note that when there is more than one listener, they are in a list,
|
||||
so there is an order. In this case <methodname>open</methodname> is called
|
||||
in the same order, and <methodname>onError</methodname> and
|
||||
<methodname>close</methodname> are called in reverse order.</para>
|
||||
so there is an order. In this case <methodname>open</methodname> will be
|
||||
called in the same order while <methodname>onError</methodname> and
|
||||
<methodname>close</methodname> will be called in reverse order.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<section id="chunkOrientedProcessing">
|
||||
<title>Chunk-Oriented Processing</title>
|
||||
|
||||
<para>Spring Batch uses a 'Chunk Oriented' processing style within it's
|
||||
<para>Spring Batch uses a 'Chunk Oriented' processing style within its
|
||||
most common implementation. Chunk oriented processing refers to reading
|
||||
the data one at a time, and creating 'chunks' that will be written out,
|
||||
within a transaction boundary. One item is read in from an
|
||||
@@ -61,7 +61,8 @@
|
||||
<programlisting>
|
||||
List items = new Arraylist();
|
||||
for(int i = 0; i < commitInterval; i++){
|
||||
Object processedItem = itemProcessor.process(itemReader.read());
|
||||
Object item = itemReader.read()
|
||||
Object processedItem = itemProcessor.process(item);
|
||||
items.add(processedItem);
|
||||
}
|
||||
itemWriter.write(items);
|
||||
@@ -120,8 +121,9 @@
|
||||
|
||||
<para>It should be noted that, job-repository defaults to
|
||||
"jobRepository" and transaction-manager defaults to "transactionManger".
|
||||
Furthermore, the ItemProcessor is not required, since the item could be
|
||||
directly passed from the reader to the writer.</para>
|
||||
Furthermore, the <classname>ItemProcessor</classname> is optional, not
|
||||
required, since the item could be directly passed from the reader to the
|
||||
writer.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -130,13 +132,14 @@
|
||||
<para>As mentioned above, a step reads in and writes out items,
|
||||
periodically committing using the supplied
|
||||
<classname>PlatformTransactionManager</classname>. With a
|
||||
commit-interval of 1, it will commit after writing only one item. This
|
||||
is less than ideal in many situations, since beginning and committing a
|
||||
transaction is expensive. Ideally, it is preferable to process as many
|
||||
items as possible in each transaction, which is completely dependent
|
||||
upon the type of data being processed and the resources with which the
|
||||
step is interacting. For this reason, the number of items that are
|
||||
processed within a commit can be configured.</para>
|
||||
commit-interval of 1, it will commit after writing each individual item.
|
||||
This is less than ideal in many situations, since beginning and
|
||||
committing a transaction is expensive. Ideally, it is preferable to
|
||||
process as many items as possible in each transaction, which is
|
||||
completely dependent upon the type of data being processed and the
|
||||
resources with which the step is interacting. For this reason, the
|
||||
number of items that are processed within a commit can be
|
||||
configured.</para>
|
||||
|
||||
<programlisting>
|
||||
<job id="sampleJob">
|
||||
@@ -168,14 +171,15 @@
|
||||
<title>Setting a StartLimit</title>
|
||||
|
||||
<para>There are many scenarios where you may want to control the
|
||||
number of times a <classname>Step</classname> may be started. An
|
||||
example is a <classname>Step</classname> that may be run only once,
|
||||
usually because it invalidates some resource that must be fixed
|
||||
manually before it can be run again. This is configurable on the step
|
||||
level, since different steps have different requirements. One Step
|
||||
that may only be executed once can exist as part of the same
|
||||
<classname>Job</classname> as <classname>Step</classname> that can be
|
||||
run infinitely. Below is an example start limit configuration:</para>
|
||||
number of times a <classname>Step</classname> may be started. For
|
||||
example, a particular <classname>Step</classname> might need to be
|
||||
configured so that it only runs once because it invalidates some
|
||||
resource that must be fixed manually before it can be run again. This
|
||||
is configurable on the step level, since different steps may have
|
||||
different requirements. A <classname>Step</classname> that may only be
|
||||
executed once can exist as part of the same <classname>Job</classname>
|
||||
as a <classname>Step</classname> that can be run infinitely. Below is
|
||||
an example start limit configuration:</para>
|
||||
|
||||
<programlisting>
|
||||
<step name="step1">
|
||||
@@ -323,7 +327,7 @@
|
||||
<listitem>
|
||||
<para>playerSummarization is not start, and the job is immediately
|
||||
killed, since this is the third execution of playerSummarization,
|
||||
and it's limit is only 2. The limit must either be raised, or the
|
||||
and its limit is only 2. The limit must either be raised, or the
|
||||
<classname>Job</classname> must be executed as a new
|
||||
<classname>JobInstance</classname>.</para>
|
||||
</listitem>
|
||||
@@ -361,15 +365,15 @@
|
||||
<classname>FlatFileParseException</classname> is thrown, it will be
|
||||
skipped and counted against the total skip limit of 10. It should be
|
||||
noted that any failures encountered while reading will not count against
|
||||
the commit interval. In other words, the commit interval is only
|
||||
incremented on writes (regardless of success or failure).</para>
|
||||
the skip limit. In other words, the skip limit is only incremented on
|
||||
writes (regardless of success or failure).</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<para>One problem with the example above is that any other exception
|
||||
besides a <classname>FlatFileParseException</classname> will cause the
|
||||
<classname>Job</classname> to fail. In certain scenarios this may be the
|
||||
correct behaviour, however, in certain scenarios it may be easier to
|
||||
correct behavior. However, in other scenarios it may be easier to
|
||||
identify which exceptions should cause failure and skip everything
|
||||
else:<programlisting>
|
||||
<step name="step1">
|
||||
@@ -398,8 +402,8 @@
|
||||
<para>In most cases you want an exception to cause either a skip or
|
||||
<classname>Step</classname> failure. However, not all exceptions are
|
||||
deterministic. If a <classname>FlatFileParseException</classname> is
|
||||
encountered while reading, it will always be thrown for that record.
|
||||
Resetting the <classname>ItemReader</classname> will not help. However,
|
||||
encountered while reading, it will always be thrown for that record;
|
||||
resetting the <classname>ItemReader</classname> will not help. However,
|
||||
for other exceptions, such as a
|
||||
<classname>DeadlockLoserDataAccessException</classname>, which indicates
|
||||
that the current process has attempted to update a record that another
|
||||
@@ -438,7 +442,8 @@
|
||||
the <classname>Step</classname> can be configured with a list of
|
||||
exceptions that should not cause rollback. The transaction-attribute
|
||||
attribute is a comma-separated list. Prefixing a class name with the "+"
|
||||
symbol will indicate that exception should not cause rollback.</para>
|
||||
symbol will indicate that that exception should not cause
|
||||
rollback.</para>
|
||||
|
||||
<programlisting>
|
||||
<step name="step1">
|
||||
@@ -450,8 +455,8 @@
|
||||
</programlisting>
|
||||
|
||||
<para>Transaction attributes can be used to control multiple other
|
||||
settings such as isolation and propagation behaviour. More information
|
||||
on setting transaction attributes can be found in the spring core
|
||||
settings such as isolation and propagation behavior. More information on
|
||||
setting transaction attributes can be found in the spring core
|
||||
documentation.</para>
|
||||
|
||||
<section id="transactionalReaders">
|
||||
@@ -483,21 +488,21 @@
|
||||
|
||||
<para>The step has to take care of <classname>ItemStream</classname>
|
||||
callbacks at the necessary points in its lifecycle. (for more
|
||||
information on the ItemStream interface, please refer to <xref
|
||||
linkend="itemStream" />) This is vital if a step fails, and might need
|
||||
to be restarted, because the <classname>ItemStream</classname> interface
|
||||
is where the step gets the information it needs about persistent state
|
||||
between executions.</para>
|
||||
information on the <classname>ItemStream</classname> interface, please
|
||||
refer to <xref linkend="itemStream" />) This is vital if a step fails,
|
||||
and might need to be restarted, because the
|
||||
<classname>ItemStream</classname> interface is where the step gets the
|
||||
information it needs about persistent state between executions.</para>
|
||||
|
||||
<para>If the <classname>ItemReader</classname>,
|
||||
<classname>ItemProcessor</classname>, or
|
||||
<classname>ItemWriter</classname> itself implements the
|
||||
<classname>ItemStream</classname> interface, then these will be
|
||||
registered automatically. Any other streams need to be registered
|
||||
separately. This is often the case where there are indirect
|
||||
dependencies, like delegates being injected into the reader and writer.
|
||||
To a stream it can be injected into the <classname>Step</classname>
|
||||
through the 'streams' element, as illustrated below:</para>
|
||||
separately. This is often the case where there are indirect dependencies
|
||||
such as delegates being injected into the reader and writer. A stream
|
||||
can be registered on the <classname>Step</classname> through the
|
||||
'streams' element, as illustrated below:</para>
|
||||
|
||||
<programlisting>
|
||||
<step name="step1">
|
||||
@@ -526,11 +531,11 @@
|
||||
<classname>ItemStream</classname>, but both of its delegates are.
|
||||
Therefore, both delegate writers must be explicitly registered as
|
||||
streams in order for the framework to handle them correctly. The
|
||||
<classname>ItemReader</classname> does not need to explicitly registered
|
||||
as a stream because it is a direct property of the
|
||||
<classname>ItemReader</classname> does not need to be explicitly
|
||||
registered as a stream because it is a direct property of the
|
||||
<classname>Step</classname>. The step will now be restartable and the
|
||||
state of the reader and writer will be correctly persisted in case of a
|
||||
failure.</para>
|
||||
state of the reader and writer will be correctly persisted in the event
|
||||
of a failure.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -560,7 +565,7 @@
|
||||
</programlisting>
|
||||
|
||||
<para>In addition to the <classname>StepListener</classname> interfaces,
|
||||
annotations are provided address the same concerns.</para>
|
||||
annotations are provided to address the same concerns.</para>
|
||||
|
||||
<section>
|
||||
<title>StepExecutionListener</title>
|
||||
@@ -763,9 +768,10 @@
|
||||
<section>
|
||||
<title>SkipListener</title>
|
||||
|
||||
<para>Both <classname>ItemReadListener</classname> and
|
||||
<classname>ItemWriteListner</classname> provide a mechanism for being
|
||||
notified of errors, but neither one will inform you that a record has
|
||||
<para><classname>ItemReadListener</classname>,
|
||||
<classname>ItemProcessListener</classname>, and
|
||||
<classname>ItemWriteListner</classname> all provide mechanisms for
|
||||
being notified of errors, but none will inform you that a record has
|
||||
actually been skipped. <methodname>onWriteError</methodname>, for
|
||||
example, will be called even if an item is retried and successful. For
|
||||
this reason, there is a separate interface for tracking skipped
|
||||
@@ -776,9 +782,9 @@
|
||||
|
||||
void onSkipInRead(Throwable t);
|
||||
|
||||
void onSkipInWrite(S item, Throwable t);
|
||||
|
||||
void onSkipInProcess(T item, Throwable t);
|
||||
|
||||
void onSkipInWrite(S item, Throwable t);
|
||||
}
|
||||
|
||||
</programlisting>
|
||||
@@ -814,8 +820,8 @@
|
||||
<classname>SkipListener</classname> is to log out a skipped item, so
|
||||
that another batch process or even human process can be used to
|
||||
evaluate and fix the issue leading to the skip. Because there are
|
||||
many cases in which the original trasaction may be rolledback,
|
||||
Spring Batch makes two garantees:</para>
|
||||
many cases in which the original transaction may be rolled back,
|
||||
Spring Batch makes two guarantees:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
@@ -863,8 +869,8 @@
|
||||
</programlisting>
|
||||
|
||||
<note>
|
||||
<para>TaskletStep will automatically register the tasklet as
|
||||
<classname>StepExecutionListener</classname> if it implements this
|
||||
<para><classname>TaskletStep</classname> will automatically register the
|
||||
tasklet as <classname>StepListener</classname> if it implements this
|
||||
interface</para>
|
||||
</note>
|
||||
|
||||
@@ -896,7 +902,7 @@
|
||||
<title>Example Tasklet implementation</title>
|
||||
|
||||
<para>Many batch jobs contain steps that must be done before the main
|
||||
processing begins in order to set up various resources, or after
|
||||
processing begins in order to set up various resources or after
|
||||
processing has completed to cleanup those resources. In the case of a
|
||||
job that works heavily with files, it is often necessary to delete
|
||||
certain files locally after they have been uploaded successfully to
|
||||
@@ -962,8 +968,8 @@
|
||||
<para>With the ability to group steps together within an owning job, comes
|
||||
the need to be able to control how the job 'flows' from one step to
|
||||
another. The failure of a <classname>Step</classname> doesn't necessarily
|
||||
mean that the <classname>Job</classname> should fail. Further, there may
|
||||
be more than one type of 'success', which determines which
|
||||
mean that the <classname>Job</classname> should fail. Furthermore, there
|
||||
may be more than one type of 'success', which determines which
|
||||
<classname>Step</classname> should be executed next. Depending upon how a
|
||||
group of Steps is configured, certain steps may not even be processed at
|
||||
all.</para>
|
||||
@@ -1082,7 +1088,7 @@
|
||||
<classname>ExitStatus</classname>. <classname>BatchStatus</classname>
|
||||
is an enumeration that is a property of both
|
||||
<classname>JobExecution</classname> and
|
||||
<classname>StepExecution</classname>, and is used by the framework to
|
||||
<classname>StepExecution</classname> and is used by the framework to
|
||||
record the status of a <classname>Job</classname> or
|
||||
<classname>Step</classname>. It can be one of the following values:
|
||||
COMPLETED, STARTING, STARTED, FAILED, STOPPING, STOPPED, or UNKNOWN.
|
||||
@@ -1098,18 +1104,19 @@
|
||||
|
||||
<para>At first glance, it would appear that the 'on' attribute
|
||||
references the <classname>BatchStatus</classname> of the
|
||||
<classname>Step</classname> it belongs to. However, it references the
|
||||
<classname>ExitStatus</classname> of the <classname>Step</classname>.
|
||||
As the name implies, <classname>ExitStatus</classname> represents the
|
||||
status of a <classname>Step</classname> after it finishes execution.
|
||||
More specifically, the 'next' element above references the
|
||||
<classname>Step</classname> to which it belongs. However, it
|
||||
references the <classname>ExitStatus</classname> of the
|
||||
<classname>Step</classname>. As the name implies,
|
||||
<classname>ExitStatus</classname> represents the status of a
|
||||
<classname>Step</classname> after it finishes execution. More
|
||||
specifically, the 'next' element above references the
|
||||
<classname>ExitCode</classname> of the
|
||||
<classname>ExitStatus</classname>. To write it in English, it says:
|
||||
"go to stepB if the exit code is FAILED". By default, the exit code is
|
||||
always the same as the <classname>BatchStatus</classname> for the
|
||||
Step, which is why the entry above works. However, what if the exit
|
||||
code needs to be different? A good example comes from the skip sample
|
||||
job, within the samples project:</para>
|
||||
job within the samples project:</para>
|
||||
|
||||
<programlisting>
|
||||
<step name="step1">
|
||||
@@ -1138,7 +1145,7 @@
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>The above configuration will work, however, something needs to
|
||||
<para>The above configuration will work. However, something needs to
|
||||
change the exit code based on the condition of the execution having
|
||||
skipped records:</para>
|
||||
|
||||
@@ -1160,8 +1167,8 @@
|
||||
that first checks to make sure the <classname>Step</classname> was
|
||||
successful, and next if the skip count on the
|
||||
<classname>StepExecution</classname> is higher than 0. If both
|
||||
conditions are met, a new ExitStatus with an exit code of "COMPLETED
|
||||
WITH SKIPS" is returned.</para>
|
||||
conditions are met, a new <classname>ExitStatus</classname> with an
|
||||
exit code of "COMPLETED WITH SKIPS" is returned.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -1199,8 +1206,9 @@
|
||||
<section>
|
||||
<title>Programmatic flow decisions</title>
|
||||
|
||||
<para>In some situations, more information than the exit status may be
|
||||
required to decide which step to execute next. In this case, a
|
||||
<para>In some situations, more information than the
|
||||
<classname>ExitStatus</classname> may be required to decide which step
|
||||
to execute next. In this case, a
|
||||
<classname>JobExecutionDecider</classname> can be used to assist in the
|
||||
decision.</para>
|
||||
|
||||
@@ -1261,10 +1269,10 @@
|
||||
</programlisting>
|
||||
|
||||
<para>The above <classname>Resource</classname> will load the file from
|
||||
the file system, at the location specified. Note that absolute locations
|
||||
have to start with a double slash ("//"). In most spring applications,
|
||||
this solution is good enough because the names of these are known at
|
||||
compile time. However, in batch scenarios, the file name may need to be
|
||||
the file system location specified. Note that absolute locations have to
|
||||
start with a double slash ("//"). In most spring applications, this
|
||||
solution is good enough because the names of these are known at compile
|
||||
time. However, in batch scenarios, the file name may need to be
|
||||
determined at runtime as a parameter to the job. This could be solved
|
||||
using '-D' parameters, i.e. a system property:</para>
|
||||
|
||||
@@ -1284,10 +1292,11 @@
|
||||
filters and does placeholder replacement on system properties.)</para>
|
||||
|
||||
<para>Often in a batch setting it is preferable to parameterize the file
|
||||
name in the <link linkend="jobParameters">JobParameters</link> of the
|
||||
job, instead of through system properties, and access them that way. To
|
||||
allow for this, Spring Batch allows for the late binding of various Job
|
||||
and Step attributes:</para>
|
||||
name in the <link
|
||||
linkend="jobParameters"><classname>JobParameters</classname></link> of
|
||||
the job, instead of through system properties, and access them that way.
|
||||
To accomplish this, Spring Batch allows for the late binding of various
|
||||
Job and Step attributes:</para>
|
||||
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
@@ -1305,7 +1314,7 @@
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="#{<emphasis role="bold">jobExecutionContext</emphasis>[input.file.name]}" />
|
||||
<property name="resource" value="<emphasis role="bold">#{jobExecutionContext[input.file.name]}</emphasis>" />
|
||||
</bean>
|
||||
|
||||
</programlisting>
|
||||
@@ -1313,7 +1322,7 @@
|
||||
<programlisting>
|
||||
<bean id="flatFileItemReader" scope="step"
|
||||
class="org.springframework.batch.item.file.FlatFileItemReader">
|
||||
<property name="resource" value="#{<emphasis role="bold">stepExecutionContext</emphasis>[input.file.name]}" />
|
||||
<property name="resource" value="<emphasis role="bold">#{stepExecutionContext[input.file.name]}</emphasis>" />
|
||||
</bean>
|
||||
|
||||
</programlisting>
|
||||
@@ -1333,7 +1342,7 @@
|
||||
</programlisting>
|
||||
|
||||
<para>Using a scope of <classname>Step</classname> is required in
|
||||
order to use late binding, since the bean cannot actually be
|
||||
order to use late binding since the bean cannot actually be
|
||||
instantiated until the <classname>Step</classname> starts, which
|
||||
allows the attributes to be found. Because it is not part of the
|
||||
Spring container by default, it must be added explicitly:</para>
|
||||
|
||||
Reference in New Issue
Block a user