Spring Batch and JobInstanceAlreadyCompleteException:
<p>I have a Spring Batch job which retrieves files from a remote Linux server via SFTP.
The directory on the remote server is an archive of seven days worth of files (~400 files).  The files are relatively small in size.</p>

<p>Spring Batch knows which files have already been processed.  </p>

<p>When I launch the app. the first time, a Spring Batch tasklet retrieves the files then, Spring Batch generates an exception for each file it has already processed:</p>

<p>E.g. </p>

<p>Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={input.file.url=file:///blahblahblah.txt}.</p>

<p>This causes huge delays in processing.</p>

<p>After the first time, on subsequent sftp retrievals of the files there's no exceptions and consequently no delays (perhaps Spring Batch has generated an internal hash list of files already processed).</p>

<ol>
<li><p>In the Transformer class, should I check to see if the file exists locally and only invoke JobLaunchRequest()s on the new files that have not yet been processed?</p>

<p>/**</p>

<ul>
<li><p>Transform BAI file to a Spring Batch job launch request
*/
public class FileMessageToJobRequestTransformer {
public static final Logger LOGGER = LoggerFactory.getLogger(FileMessageToJobRequestTransformer.class);
private Job job;</p>

<p>private String fileParameterName;</p>

<p>public void setJob(Job job) {
    this.job = job;
}</p>

<p>public void setFileParameterName(String fileParameterName) {
    LOGGER.debug("file parameter name: {}", fileParameterName);
    this.fileParameterName = fileParameterName;
}</p>

<p>@Transformer
public JobLaunchRequest transform(Message message) {
    LOGGER.debug("File message: {}", message);
    JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();</p>

<pre><code>jobParametersBuilder.addString(fileParameterName,
        "file://" + message.getPayload().getAbsolutePath());

LOGGER.debug("Job params: {}", jobParametersBuilder.toJobParameters());

return new JobLaunchRequest(job, jobParametersBuilder.toJobParameters());
</code></pre>

<p>}
}</p></li>
</ul></li>
<li><p>Is there a way I can catch the exception?</p></li>
</ol>

<p>JobInstanceAlreadyCompleteException</p>

<ol start="3">
<li>Should I set retry-limit="1" and skip-limit="1" in SftpBaiParserJobBridge-context.hml?</li>
</ol>

<p><code>
    &lt;!-- When getting a new BAI file, transform into spring batch job request --&gt;
        &lt;int:transformer id="fileMessageToJobRequestTransformer"
                         input-channel="inboundFileChannel"
                         output-channel="outboundJobRequestChannel"
                         method="transform"&gt;
            &lt;bean class="com.distributedfinance.mbi.bai.transformer.FileMessageToJobRequestTransformer"&gt;
                &lt;property name="job" ref="baiParseJob"/&gt;
                &lt;property name="fileParameterName" value="input.file.url"/&gt;
            &lt;/bean&gt;
            &lt;int:poller fixed-rate="10000"/&gt;
        &lt;/int:transformer&gt;
</code></p>

<p>appending addDate() has allowed files to be processed multiple times.
There are now dups in the database.</p>

<pre><code>jobParametersBuilder.addString(fileParameterName,
                "file://" + message.getPayload().getAbsolutePath())).addDate("rundate", new Date()).toJobParameters();
</code></pre>

<p><a href="https://i.stack.imgur.com/TB6eY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/TB6eY.png" alt="enter image description here"></a>
Thanks!</p>

<ol start="4">
<li>Can I check determine whether the file has already been processed by querying the repository via the JobExplorer interface from inside '@Transformer
public JobLaunchRequest transform(Message message)' and returning null if the file has already been processed?</li>
</ol>

<p>E.g. </p>

<pre><code>public interface JobExplorer {

    List&lt;JobInstance&gt; getJobInstances(String jobName, int start, int count);

    JobExecution getJobExecution(Long executionId);

    StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId);

    JobInstance getJobInstance(Long instanceId);

    List&lt;JobExecution&gt; getJobExecutions(JobInstance jobInstance);

    Set&lt;JobExecution&gt; findRunningJobExecutions(String jobName);
}
</code></pre>

<ol start="5">
<li><p>How do I catch the exception?</p>

<p>Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={input.file.url=file:///home/dlaxer/dfc-bank-integration/mbi-application/bai/download/BAI_Intraday160302070054471.txt}.  If you want to run this job again, change the parameters.
        at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:126)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:172)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
        at com.sun.proxy.$Proxy113.createJobExecution(Unknown Source)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:125)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
        at com.sun.proxy.$Proxy114.run(Unknown Source)
        at org.springframework.batch.integration.launch.JobLaunchingMessageHandler.launch(JobLaunchingMessageHandler.java:50)
        at org.springframework.batch.integration.launch.JobLaunchingGateway.handleRequestMessage(JobLaunchingGateway.java:76)
        ... 35 more</p></li>
</ol>