在基于块的步骤中中止批处理作业
Aborting a Batch Job during a chunk-based step
我在 Spring 批处理中设置了一个有点线性的作业,它由几个步骤组成。如果在任何时候,单个步骤失败,则作业应该失败。
这些步骤由许多 tasklet 和一个基于块的步骤组成。即:
- 第一步
- 任务集 1
- 第 2 步
- 小任务 2
- 步骤 3
- Reader
- 处理器
- 作家
如果出现问题,显而易见的事情就是抛出异常。 Spring Batch 将处理此问题并记录所有内容。这种行为,尤其是打印堆栈跟踪,是不可取的,如果可以在 Status 设置为 FAILED
.
的情况下优雅地结束作业会更好
Tasklet 当前直接在 StepContribution
上设置 ExitStatus
。它们也是使用流程构建的(这并不理想,但步骤继续不受阻碍)。然后可以直接在 Tasklet 中处理这些问题。
但是,我们无法访问基于块的方法中的 StepContribution
。我们只有 StepExecution
。使用 setExitStatus
在这里什么都不做。
我们使用的是构建器(JobBuilerFactory
和 StepBuilderFactory
),而不是 XML 设置。
可能的解决方案:
- 告知或配置 Batch 如何处理异常(不打印堆栈跟踪)。
- 在侦听器中捕获异常。不幸的是,当它到达
@AfterStep
. 时,异常已经被 Spring 批处理捕获
- 告诉 step/job 我们不想继续(例如,在执行上下文中设置一个值或
StepContribution
的替代项。
我认为您可以探索以下两个选项。
选项 1: 您可以使用 noSkip
Exception。
这显式地防止某些异常(和子类)被跳过
抛出一些您希望作业失败的特定异常。
这是配置帽子的方法
stepBuilderFactory.get("myStep")
.<POJO, POJO> chunk(1000)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant()
.noSkip(YourCustomException.class)
.skip(Exception.class)
.skipLimit(100)
****选项 2** :** 您可以将退出状态设置为 FAILED,以便在步骤完成后进入错误流程
public class MyStepExecutionListener implements StepExecutionListener {
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
if(allIsGood()) //
{
return ExitStatus.COMPLETED;
}
else if (someExceptionOrErrorCase()){
return ExitStatus.FAILED;
}
}
}
希望这对您有所帮助
据我所知,停止作业的唯一方法是抛出异常。没有其他优雅的方式来告诉 Spring 批次 "This job is done, it failed, go directly to Failed, do not pass GO, etc."
虽然不是原始问题的直接解决方案,但可以使用 StepBuilder
的 .exceptionHandler()
来更好地控制抛出的异常,例如记录它们。
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;
}
}
理论上,这样您可以隐藏 Spring Batch 生成的堆栈跟踪,但仍会显示错误消息。
在我的例子中,我最终添加了条件并在 Reader 和 Processor
中抛出了 JobInterruptedException
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobInterruptedException;
public class CustomReader implements ItemReader<String> {
@Override
public String read() throws Exception {
// ...
// if ("condition to stop job") {
throw new JobInterruptedException("Aborting Job", BatchStatus.ABANDONED);
// }
}
}
我在 Spring 批处理中设置了一个有点线性的作业,它由几个步骤组成。如果在任何时候,单个步骤失败,则作业应该失败。
这些步骤由许多 tasklet 和一个基于块的步骤组成。即:
- 第一步
- 任务集 1
- 第 2 步
- 小任务 2
- 步骤 3
- Reader
- 处理器
- 作家
如果出现问题,显而易见的事情就是抛出异常。 Spring Batch 将处理此问题并记录所有内容。这种行为,尤其是打印堆栈跟踪,是不可取的,如果可以在 Status 设置为 FAILED
.
Tasklet 当前直接在 StepContribution
上设置 ExitStatus
。它们也是使用流程构建的(这并不理想,但步骤继续不受阻碍)。然后可以直接在 Tasklet 中处理这些问题。
但是,我们无法访问基于块的方法中的 StepContribution
。我们只有 StepExecution
。使用 setExitStatus
在这里什么都不做。
我们使用的是构建器(JobBuilerFactory
和 StepBuilderFactory
),而不是 XML 设置。
可能的解决方案:
- 告知或配置 Batch 如何处理异常(不打印堆栈跟踪)。
- 在侦听器中捕获异常。不幸的是,当它到达
@AfterStep
. 时,异常已经被 Spring 批处理捕获
- 告诉 step/job 我们不想继续(例如,在执行上下文中设置一个值或
StepContribution
的替代项。
我认为您可以探索以下两个选项。
选项 1: 您可以使用 noSkip
Exception。
这显式地防止某些异常(和子类)被跳过 抛出一些您希望作业失败的特定异常。
这是配置帽子的方法
stepBuilderFactory.get("myStep")
.<POJO, POJO> chunk(1000)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant()
.noSkip(YourCustomException.class)
.skip(Exception.class)
.skipLimit(100)
****选项 2** :** 您可以将退出状态设置为 FAILED,以便在步骤完成后进入错误流程
public class MyStepExecutionListener implements StepExecutionListener {
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
if(allIsGood()) //
{
return ExitStatus.COMPLETED;
}
else if (someExceptionOrErrorCase()){
return ExitStatus.FAILED;
}
}
}
希望这对您有所帮助
据我所知,停止作业的唯一方法是抛出异常。没有其他优雅的方式来告诉 Spring 批次 "This job is done, it failed, go directly to Failed, do not pass GO, etc."
虽然不是原始问题的直接解决方案,但可以使用 StepBuilder
的 .exceptionHandler()
来更好地控制抛出的异常,例如记录它们。
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;
}
}
理论上,这样您可以隐藏 Spring Batch 生成的堆栈跟踪,但仍会显示错误消息。
在我的例子中,我最终添加了条件并在 Reader 和 Processor
中抛出了JobInterruptedException
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobInterruptedException;
public class CustomReader implements ItemReader<String> {
@Override
public String read() throws Exception {
// ...
// if ("condition to stop job") {
throw new JobInterruptedException("Aborting Job", BatchStatus.ABANDONED);
// }
}
}