Files
spring-batch/build/reference-epub-work/ch03s03.xhtml
Michael Minella 75ab909314 update
2017-03-23 10:18:33 -05:00

120 lines
11 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:pls="http://www.w3.org/2005/01/pronunciation-lexicon" xmlns:ssml="http://www.w3.org/2001/10/synthesis" xmlns:svg="http://www.w3.org/2000/svg"><head><title>ExecutionContext</title><link rel="stylesheet" type="text/css" href="docbook-epub.css"/><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"/><link rel="prev" href="ch03s02.xhtml" title="Step"/><link rel="next" href="ch03s04.xhtml" title="JobRepository"/></head><body><header/><section class="section" title="ExecutionContext" epub:type="subchapter" id="domainExecutionContext"><div class="titlepage"><div><div><h2 class="title" style="clear: both">ExecutionContext</h2></div></div></div>
<p>An <code class="classname">ExecutionContext</code> represents a collection
of key/value pairs that are persisted and controlled by the framework in
order to allow developers a place to store persistent state that is scoped
to a <code class="classname">StepExecution</code> or
<code class="classname">JobExecution</code>. For those familiar with Quartz, it is
very similar to <code class="classname">JobDataMap</code>. The best usage example
is to facilitate restart. Using flat file input as an example, while
processing individual lines, the framework periodically persists the
<code class="classname">ExecutionContext</code> at commit points. This allows the
<code class="classname">ItemReader</code> to store its state in case a fatal error
occurs during the run, or even if the power goes out. All that is needed
is to put the current number of lines read into the context, and the
framework will do the rest:</p>
<pre class="programlisting">executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());</pre>
<p>Using the EndOfDay example from the Job Stereotypes section as an
example, assume there's one step: 'loadData', that loads a file into the
database. After the first failed run, the meta data tables would look like
the following:</p>
<div class="table" id="d5e704"><div class="table-title">Table 3.9. BATCH_JOB_INSTANCE</div><div class="table-contents">
<table style="border-collapse: collapse; border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; "><colgroup><col/><col/></colgroup><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">JOB_INST_ID</td><td style="border-bottom: 0.5pt solid ; ">JOB_NAME</td></tr><tr><td style="border-right: 0.5pt solid ; ">1</td><td>EndOfDayJob</td></tr></tbody></table>
</div></div><div class="table" id="d5e714"><div class="table-title">Table 3.10. BATCH_JOB_PARAMS</div><div class="table-contents">
<table style="border-collapse: collapse; border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; "><colgroup><col/><col/><col/><col/></colgroup><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">JOB_INST_ID</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">TYPE_CD</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">KEY_NAME</td><td style="border-bottom: 0.5pt solid ; ">DATE_VAL</td></tr><tr><td style="border-right: 0.5pt solid ; ">1</td><td style="border-right: 0.5pt solid ; ">DATE</td><td style="border-right: 0.5pt solid ; ">schedule.Date</td><td>2008-01-01</td></tr></tbody></table>
</div></div><div class="table" id="d5e728"><div class="table-title">Table 3.11. BATCH_JOB_EXECUTION</div><div class="table-contents">
<table style="border-collapse: collapse; border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; "><colgroup><col/><col/><col/><col/><col/></colgroup><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">JOB_EXEC_ID</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">JOB_INST_ID</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">START_TIME</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">END_TIME</td><td style="border-bottom: 0.5pt solid ; ">STATUS</td></tr><tr><td style="border-right: 0.5pt solid ; ">1</td><td style="border-right: 0.5pt solid ; ">1</td><td style="border-right: 0.5pt solid ; ">2008-01-01 21:00</td><td style="border-right: 0.5pt solid ; ">2008-01-01 21:30</td><td>FAILED</td></tr></tbody></table>
</div></div><div class="table" id="d5e744"><div class="table-title">Table 3.12. BATCH_STEP_EXECUTION</div><div class="table-contents">
<table style="border-collapse: collapse; border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; "><colgroup><col/><col/><col/><col/><col/><col/></colgroup><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">STEP_EXEC_ID</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">JOB_EXEC_ID</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">STEP_NAME</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">START_TIME</td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">END_TIME</td><td style="border-bottom: 0.5pt solid ; ">STATUS</td></tr><tr><td style="border-right: 0.5pt solid ; ">1</td><td style="border-right: 0.5pt solid ; ">1</td><td style="border-right: 0.5pt solid ; ">loadData</td><td style="border-right: 0.5pt solid ; ">2008-01-01 21:00</td><td style="border-right: 0.5pt solid ; ">2008-01-01 21:30</td><td>FAILED</td></tr></tbody></table>
</div></div><div class="table" id="d5e762"><div class="table-title">Table 3.13. BATCH_STEP_EXECUTION_CONTEXT</div><div class="table-contents">
<table style="border-collapse: collapse; border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; border-left: 0.5pt solid ; border-right: 0.5pt solid ; "><colgroup><col/><col/></colgroup><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; ">STEP_EXEC_ID</td><td style="border-bottom: 0.5pt solid ; ">SHORT_CONTEXT</td></tr><tr><td style="border-right: 0.5pt solid ; ">1</td><td>{piece.count=40321}</td></tr></tbody></table>
</div></div><p>In this case, the <code class="classname">Step</code> ran for 30 minutes
and processed 40,321 'pieces', which would represent lines in a file in
this scenario. This value will be updated just before each commit by the
framework, and can contain multiple rows corresponding to entries within
the <code class="classname">ExecutionContext</code>. Being notified before a
commit requires one of the various <code class="classname">StepListener</code>s,
or an <code class="classname">ItemStream</code>, which are discussed in more
detail later in this guide. As with the previous example, it is assumed
that the <code class="classname">Job</code> is restarted the next day. When it is
restarted, the values from the <code class="classname">ExecutionContext</code> of
the last run are reconstituted from the database, and when the
<code class="classname">ItemReader</code> is opened, it can check to see if it has
any stored state in the context, and initialize itself from there:</p>
<pre class="programlisting">if (executionContext.containsKey(getKey(LINES_READ_COUNT))) {
log.debug("Initializing for restart. Restart data is: " + executionContext);
long lineCount = executionContext.getLong(getKey(LINES_READ_COUNT));
LineReader reader = getReader();
Object record = "";
while (reader.getPosition() &lt; lineCount &amp;&amp; record != null) {
record = readLine();
}
}</pre>
<p>In this case, after the above code is executed, the current line
will be 40,322, allowing the <code class="classname">Step</code> to start again
from where it left off. The <code class="classname">ExecutionContext</code> can
also be used for statistics that need to be persisted about the run
itself. For example, if a flat file contains orders for processing that
exist across multiple lines, it may be necessary to store how many orders
have been processed (which is much different from than the number of lines
read) so that an email can be sent at the end of the
<code class="classname">Step</code> with the total orders processed in the body.
The framework handles storing this for the developer, in order to
correctly scope it with an individual <code class="classname">JobInstance</code>.
It can be very difficult to know whether an existing
<code class="classname">ExecutionContext</code> should be used or not. For
example, using the 'EndOfDay' example from above, when the 01-01 run
starts again for the second time, the framework recognizes that it is the
same <code class="classname">JobInstance</code> and on an individual
<code class="classname">Step</code> basis, pulls the
<code class="classname">ExecutionContext</code> out of the database and hands it
as part of the <code class="classname">StepExecution</code> to the
<code class="classname">Step</code> itself. Conversely, for the 01-02 run the
framework recognizes that it is a different instance, so an empty context
must be handed to the <code class="classname">Step</code>. There are many of these
types of determinations that the framework makes for the developer to
ensure the state is given to them at the correct time. It is also
important to note that exactly one <code class="classname">ExecutionContext</code>
exists per <code class="classname">StepExecution</code> at any given time. Clients
of the <code class="classname">ExecutionContext</code> should be careful because
this creates a shared keyspace, so care should be taken when putting
values in to ensure no data is overwritten. However, the
<code class="classname">Step</code> stores absolutely no data in the context, so
there is no way to adversely affect the framework.</p>
<p>It is also important to note that there is at least one
<code class="classname">ExecutionContext</code> per
<code class="classname">JobExecution</code>, and one for every
<code class="classname">StepExecution</code>. For example, consider the following
code snippet:</p>
<pre class="programlisting">ExecutionContext ecStep = stepExecution.getExecutionContext();
ExecutionContext ecJob = jobExecution.getExecutionContext();
//ecStep does not equal ecJob</pre>
<p>As noted in the comment, ecStep will not equal ecJob; they are two
different <code class="classname">ExecutionContext</code>s. The one scoped to the
<code class="classname">Step</code> will be saved at every commit point in the
<code class="classname">Step</code>, whereas the one scoped to the
<code class="classname">Job</code> will be saved in between every
<code class="classname">Step</code> execution.</p>
</section><footer/></body></html>