90 lines
4.5 KiB
HTML
90 lines
4.5 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>Stopping a Job Manually for Business Reasons</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="ch11.xhtml" title="Chapter 11. Common Batch Patterns"/><link rel="next" href="ch11s03.xhtml" title="Adding a Footer Record"/></head><body><header/><section class="section" title="Stopping a Job Manually for Business Reasons" epub:type="subchapter" id="stoppingAJobManuallyForBusinessReasons"><div class="titlepage"><div><div><h2 class="title" style="clear: both">Stopping a Job Manually for Business Reasons</h2></div></div></div>
|
||
|
||
|
||
<p>Spring Batch provides a <code class="methodname">stop</code>() method
|
||
through the <code class="classname">JobLauncher</code> interface, but this is
|
||
really for use by the operator rather than the application programmer.
|
||
Sometimes it is more convenient or makes more sense to stop a job
|
||
execution from within the business logic.</p>
|
||
|
||
<p>The simplest thing to do is to throw a
|
||
<code class="classname">RuntimeException</code> (one that isn't retried
|
||
indefinitely or skipped). For example, a custom exception type could be
|
||
used, as in the example below:</p>
|
||
|
||
<pre class="programlisting">public class PoisonPillItemWriter implements ItemWriter<T> {
|
||
|
||
public void write(T item) throws Exception {
|
||
if (isPoisonPill(item)) {
|
||
throw new PoisonPillException("Posion pill detected: " + item);
|
||
}
|
||
}
|
||
|
||
}</pre>
|
||
|
||
<p>Another simple way to stop a step from executing is to simply return
|
||
<code class="code">null</code> from the <code class="classname">ItemReader</code>:</p>
|
||
|
||
<pre class="programlisting">public class EarlyCompletionItemReader implements ItemReader<T> {
|
||
|
||
private ItemReader<T> delegate;
|
||
|
||
public void setDelegate(ItemReader<T> delegate) { ... }
|
||
|
||
public T read() throws Exception {
|
||
T item = delegate.read();
|
||
if (isEndItem(item)) {
|
||
return null; // end the step here
|
||
}
|
||
return item;
|
||
}
|
||
|
||
}</pre>
|
||
|
||
<p>The previous example actually relies on the fact that there is a
|
||
default implementation of the <code class="classname">CompletionPolicy</code>
|
||
strategy which signals a complete batch when the item to be processed is
|
||
null. A more sophisticated completion policy could be implemented and
|
||
injected into the <code class="classname">Step</code> through the
|
||
<code class="classname">SimpleStepFactoryBean</code>:</p>
|
||
|
||
<pre class="programlisting"><step id="simpleStep">
|
||
<tasklet>
|
||
<chunk reader="reader" writer="writer" commit-interval="10"
|
||
<span class="bold"><strong>chunk-completion-policy="completionPolicy"</strong></span>/>
|
||
</tasklet>
|
||
</step>
|
||
|
||
<bean id="completionPolicy" class="org.example...SpecialCompletionPolicy"/></pre>
|
||
|
||
<p>An alternative is to set a flag in the
|
||
<code class="classname">StepExecution</code>, which is checked by the
|
||
<code class="classname">Step</code> implementations in the framework in between
|
||
item processing. To implement this alternative, we need access to the
|
||
current <code class="classname">StepExecution</code>, and this can be achieved by
|
||
implementing a <code class="classname">StepListener</code> and registering it with
|
||
the <code class="classname">Step</code>. Here is an example of a listener that
|
||
sets the flag:</p>
|
||
|
||
<pre class="programlisting">public class CustomItemWriter extends ItemListenerSupport implements StepListener {
|
||
|
||
private StepExecution stepExecution;
|
||
|
||
public void beforeStep(StepExecution stepExecution) {
|
||
this.stepExecution = stepExecution;
|
||
}
|
||
|
||
public void afterRead(Object item) {
|
||
if (isPoisonPill(item)) {
|
||
stepExecution.setTerminateOnly(true);
|
||
}
|
||
}
|
||
|
||
}</pre>
|
||
|
||
<p>The default behavior here when the flag is set is for the step to
|
||
throw a <code class="classname">JobInterruptedException</code>. This can be
|
||
controlled through the <code class="classname">StepInterruptionPolicy</code>, but
|
||
the only choice is to throw or not throw an exception, so this is always
|
||
an abnormal ending to a job.</p>
|
||
</section><footer/></body></html> |