120 lines
11 KiB
HTML
120 lines
11 KiB
HTML
<?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() < lineCount && 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> |