Can't get spring batch conditional flows worki

2019-05-08 19:33发布

问题:

I'm having trouble getting a conditional spring batch flow to work using java config. The samples I've seen in spring batch samples, or spring batch's test code, or on stack overflow tend to show a conditional where a single step needs to be executed on condition, or it's the final step, or both. That's not the case I need to solve.

In procedural pseudo code, I want it to behave like

initStep()
if decision1()
    subflow1()
middleStep()
if decision2()
    subflow2()
lastStep()

So, subflow1 and 2 are conditional, but init, middle and last always execute. Here's my stripped down test case. In the current configuration, it just quits after executing subflow1.

public class FlowJobTest {

private JobBuilderFactory jobBuilderFactory;
private JobRepository jobRepository;
private JobExecution execution;

@BeforeMethod
public void setUp() throws Exception {
    jobRepository = new MapJobRepositoryFactoryBean().getObject();
    jobBuilderFactory = new JobBuilderFactory(jobRepository);
    execution = jobRepository.createJobExecution("flow", new JobParameters());
}

@Test
public void figureOutFlowJobs() throws Exception {

    JobExecutionDecider subflow1Decider = decider(true);
    JobExecutionDecider subflow2Decider = decider(false);

    Flow subflow1 = new FlowBuilder<Flow>("subflow-1").start(echo("subflow-1-Step-1")).next(echo("subflow-1-Step-2")).end();
    Flow subflow2 = new FlowBuilder<Flow>("subflow-2").start(echo("subflow-2-Step-1")).next(echo("subflow-2-Step-2")).end();

    Job job = jobBuilderFactory.get("testJob")
            .start(echo("init"))

            .next(subflow1Decider)
                .on("YES").to(subflow1)
            .from(subflow1Decider)
                .on("*").to(echo("middle"))
            .next(subflow2Decider)
                .on("YES").to(subflow2)
            .from(subflow2Decider)
                .on("*").to(echo("last"))

            .next(echo("last"))
            .build().preventRestart().build();

    job.execute(execution);
    assertEquals(execution.getStatus(), BatchStatus.COMPLETED);
    assertEquals(execution.getStepExecutions().size(), 5);
}


private Step echo(String stepName) {
    return new AbstractStep() {
        {
            setName(stepName);
            setJobRepository(jobRepository);
        }
        @Override
        protected void doExecute(StepExecution stepExecution) throws Exception {
            System.out.println("step: " + stepName);
            stepExecution.upgradeStatus(BatchStatus.COMPLETED);
            stepExecution.setExitStatus(ExitStatus.COMPLETED);
            jobRepository.update(stepExecution);
        }
    };
}

private JobExecutionDecider decider(boolean decision) {
    return (jobExecution, stepExecution) -> new FlowExecutionStatus(decision ? "YES" : "NO");
}

}

回答1:

Your original job definition should work, as well, with only a small tweak. The test was failing because the job finished (with status COMPLETED) after the first sub flow. If you instruct it to continue to the middle step instead, it should work as intended. Similar adjustment for the second flow.

Job job = jobBuilderFactory.get("testJob")
        .start(echo("init"))

        .next(subflow1Decider)
            .on("YES").to(subflow1).next(echo("middle"))
        .from(subflow1Decider)
            .on("*").to(echo("middle"))
        .next(subflow2Decider)
            .on("YES").to(subflow2).next(echo("last"))
        .from(subflow2Decider)
            .on("*").to(echo("last"))

        .build().preventRestart().build();


回答2:

The approach I used to make this work was to break my conditional flows into flow steps.

    public void figureOutFlowJobsWithFlowStep(boolean decider1, boolean decider2, int expectedSteps) throws Exception {

    JobExecutionDecider subflow1Decider = decider(decider1);
    JobExecutionDecider subflow2Decider = decider(decider2);

    Flow subFlow1 = new FlowBuilder<Flow>("sub-1")
            .start(subflow1Decider)
            .on("YES")
            .to(echo("sub-1-1")).next(echo("sub-1-2"))
            .from(subflow1Decider)
            .on("*").end()
            .end();
    Flow subFlow2 = new FlowBuilder<Flow>("sub-2")
            .start(subflow2Decider)
            .on("YES").to(echo("sub-2-1")).next(echo("sub-2-2"))
            .from(subflow2Decider)
            .on("*").end()
            .end();

    Step subFlowStep1 = new StepBuilder("sub1step").flow(subFlow1).repository(jobRepository).build();
    Step subFlowStep2 = new StepBuilder("sub2step").flow(subFlow2).repository(jobRepository).build();

    Job job = jobBuilderFactory.get("testJob")
            .start(echo("init"))
            .next(subFlowStep1)
            .next(echo("middle"))
            .next(subFlowStep2)
            .next(echo("last"))
            .preventRestart().build();

    job.execute(execution);
    assertEquals(execution.getStatus(), BatchStatus.COMPLETED);
    assertEquals(execution.getStepExecutions().size(), expectedSteps);
}