eSKape
eSKape

Reputation: 71

Return to a previous Step in Spring Batch

I want to implement a Job similar to the following one, using Spring Batch:

Step1 -----> Step2 --> End
  ^            |
  |            |
   ------------

On some condition in Step2, determined by a custom ExitCode of Step2, either Step1 is started again and thus after it, Step2 again, or the processing will end.

What I've imagined is something like this:

return jobBuilderFactory.get("jobName").incrementer(new RunIdIncrementer())
                .start(step1()).next(step2())
                    .on("condition1").end()
                .from(step1())
                    .on("condition2").to(step1()).end().build();

But obviously, after Step1 was processed through the condition2 of Step2, Step2 won't be started again.

How can I implement such a recursive Batch Processing?

EDIT: I managed to get a solution, however, I do not know yet if it's just a dirty one, because it seems to be just to easy:

jobBuilderFactory.get("jobName")
            .flow(step1())
            .next(step2())
                .on("launchStep1Again")
                    .to(step1())
            .from(step2())
                .on("endJobExecution")
                    .end().build().build();

So the simple change from using the Fluent API's .start() method to its .flow() method seems to do the trick.

Upvotes: 3

Views: 2469

Answers (2)

Hansjoerg Wingeier
Hansjoerg Wingeier

Reputation: 4454

SpringBatch was not intended for handling recursive loops. Whilst you may be able to hack around it, you will run into problems when it comes to failures and restarting.

SpringBatch stores the current "position" of it readers and writers of a step inside its execution context; in order to be able to restart the job at the very position it crashed the last time.

Therefore, in case of a restart of the job, SpringBatch will assume that this was the first execution of the job.

Depending on your job structure, this may not be a problem, but it is something you have to keep in mind.

In my opinion, a better solution would be to implement handling the loop outside of the job, in a separate class that handles starting job.

The answers to the following two questions may help in order to come up with such a solution:

Make a spring-batch job exit with non-zero code if an exception is thrown

Reset state before each Spring scheduled (@Scheduled) run

Upvotes: 3

KayV
KayV

Reputation: 13855

I think you can extend the StepExecutionListenerSupport class and modify you configuration as follows:

<step id="step1" next="step2">
    <tasklet ref="step1Tasklet" allow-start-if-complete="true"/>
</step>
<step id="step2">
    <tasklet ref="step2Tasklet"/>
    <listeners>
        <listener ref="myListener"/>
    </listeners>
    <next on="Back" to="step1"/>
</step>

public class MyListener extends StepExecutionListenerSupport {
    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        if(wantToLoop) {
            return new ExitStatus("Back");
        } else {
            return stepExecution.getExitStatus();
        }
    }
}

Upvotes: 0

Related Questions