javaspring-batchjava-batchjberet

Java Batch Step with partition returns wrong batchStatus and exitStatus


I have a (very simple) java batch job in JDL with just two steps.

When the step "download" return the status "STOPPED" the job should stop. After restart the stop notify should be called.

Without the partition everything works fine.

stats without partition

after step=download batchStatus=COMPLETED exitStatus=STOPPED
after job=job       batchStatus=STOPPED   exitStatus=STOPPED

With partition i get realy strange stati for batch end exit. And the job doesn't stop if the download step returns "STOPPED". Even if the partition has just one thread and one partition.

When trying to restart the following error is raised (of course). JBERET000609: Job execution 1 has already completed and cannot be restarted.

stats with partition

after step=download batchStatus=STARTED   exitStatus=null
after job=job       batchStatus=COMPLETED exitStatus=COMPLETED

job descrition

<job id="job" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0" restartable="true">
    <step id="download" next="notify">
        <batchlet ref="downloadBatchlet">
        </batchlet>
        <partition>
            <mapper ref="basicPartition" />
        </partition>
        <stop on="STOPPED" restart="notify"/>
    </step>
    <step id="notify">
        <batchlet ref="notifyBatchlet"></batchlet>
        <end on="COMPLETED"/>
    </step>
</job>

Every hint an suggestions are welcome. What I am missing?

Without partition

On job start the job calls the - downloadBatchlet => STOPPED and stopps.

On restart the job calls the - notifyBatchlet => COMPLETED and ends.

With partition

On job start the job calls the - downloadBatchlet => STOPPED and stopps.

On restart the job calls NO STEPS and ends.

@Named
public class DownloadBatchlet extends AbstractBatchlet {
    @Override
    public String process() throws Exception {

        return BatchStatus.STOPPED.toString();
    }
    @Override
    public void stop() throws Exception {
    }
}

Solution

  • Partition vs Top Level Batch/Exit Status

    In Java Batch, there is a separate batch and exit status for the step itself and also for each partition.

    Since "transitioning" (to the next step, or for stopping the job, in your case) occurs at the job level here, you would need to set a non-default exit status at the "top level" of the step, not merely at the level of each partition.

    If you want to include logic which reacts to each partition's status, a good starting point would be the PartitionAnalyzer#analyzeStatus method, which is called as each partition terminates. This runs on the "top level" thread (as does the PartitionReducer).

    Simple example Analyzer

    public class MyPartitionAnalyzer extends AbstractPartitionAnalyzer {
    
        @Inject
        private StepContext stepCtx;
    
        @Override
        public void analyzeStatus(BatchStatus batchStatus, String exitStatus) throws Exception {
    
            // Overrides default exit status if non-COMPLETED partition seen
            if (!exitStatus.equals(BatchStatus.COMPLETED)) {
                stepCtx.setExitStatus(exitStatus);
            }
        }
    }
    

    You can use whatever logic you want to react (or not) to the partitions' batch and exit statuses. The key here is that the analyzer runs on the top-level step thread, and so sets the step-level status. The batchlet's return value, on the other hand, only sets the partition-level status.

    The analyzer can be used to "aggregate" partition-level status however you want. If you do nothing, the step-level exit status defaults to the step-level batch status, so if the step completes normally the step level exit status is COMPLETED.