1
votes

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.
2

2 Answers

1
votes

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.

0
votes

I think you can explore below two options.

Option 1 : You Can use noSkip Exception.

This Explicitly prevent certain exceptions (and subclasses) from being skipped Throw some specific Exception for which you want to fail the job.

This is how you can configure hat

stepBuilderFactory.get("myStep")
                .<POJO, POJO> chunk(1000)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .faultTolerant()
                .noSkip(YourCustomException.class)
                .skip(Exception.class)
                .skipLimit(100) 

****Option 2** :** You can use set the exit status to FAILED for error flow in after step is completed

public class MyStepExecutionListener implements StepExecutionListener {

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {


    if(allIsGood()) // 
    {
         return ExitStatus.COMPLETED;
    }
    else if (someExceptionOrErrorCase()){   

        return ExitStatus.FAILED;
    }
 }

 }

Hope this helps