Search code examples
javaspringexceptionspring-batchchunks

Aborting a Batch Job during a chunk-based step


I have a somewhat linear job set up in Spring Batch that consists of several steps. If, at any point, a single step fails, the job should fail.

The steps consist of a number of tasklets followed by a chunk-based step. I.e.:

  • Step 1
    • Tasklet 1
  • Step 2
    • Tasklet 2
  • Step 3
    • Reader
    • Processor
    • Writer

If something goes wrong, the obvious thing to do is throw an Exception. Spring Batch will handle this and log everything. This behaviour, particularly printing the stack trace, is undesirable, and it would be better if the Job could be ended gracefully with the Status set to FAILED.

The Tasklets currently set the ExitStatus directly on the StepContribution. They are also built using a flow (which wasn't ideal, but the steps continue unhindered otherwise). The issues can then be handled directly in the Tasklet.

However, we have no access to the StepContribution in the chunk-based approach. We only have the StepExecution. Using setExitStatus does nothing here.

We are using the builders (JobBuilerFactory and StepBuilderFactory), not the XML setups.

The potential solutions:

  1. Tell or configure Batch how to handle exceptions (not to print a stack trace).
  2. Catch the exception in a listener. Unfortunately, the exception has already been caught by Spring Batch by the time it gets to the @AfterStep.
  3. Tell the step/job that we do not want to continue (e.g. setting a value in the execution context or an alternative for the StepContribution.

Solution

  • As far as I know, the only way to stop the job is to throw an exception. There was no other graceful way of telling Spring Batch "This job is done, it failed, go directly to Failed, do not pass GO, etc."

    Although not a direct solution to the original problem, one can use the .exceptionHandler() of a StepBuilder to gain more control over the exceptions you throw, e.g. logging them.

    public class LogAndRethrowExceptionHandler implements ExceptionHandler {
        private static final Logger LOGGER = Logger.getLogger(...);
    
        @Override
        public void handleException(RepeatContext repeatContext, Throwable throwable) throws Throwable {
            LOGGER.error(throwable.getMessage());
            throw throwable;
        }
    }
    

    This way you may, in theory, hide the stack traces produced by Spring Batch but still show the error messages.