关于跳过策略实现的春季批处理中的奇怪行为

Vic*_*cky 5 spring-batch

我有一个春季批量计划.

跳过限制设置为5,块大小为1000.

我有一个工作,有两个步骤如下:

    <step id="myFileGenerator" next="myReportGenerator">
        <tasklet transaction-manager="jobRepository-transactionManager">
            <chunk reader="myItemReader" processor="myItemProcessor" writer="myItemWriter"  commit-interval="1000" skip-policy="skipPolicy"/>
        </tasklet>
        <listeners>
            <listener ref="mySkipListener"/>
        </listeners>
    </step>

    <step id="myReportGenerator">
        <tasklet ref="myReportTasklet" transaction-manager="jobRepository-transactionManager"/>
    </step> 
Run Code Online (Sandbox Code Playgroud)

跳过政策如下:

<beans:bean id="skipPolicy" class="com.myPackage.util.Skip_Policy">
    <beans:property name="skipLimit" value="5"/>
</beans:bean>
Run Code Online (Sandbox Code Playgroud)

SkipPolicy类如下:

public class Skip_Policy implements SkipPolicy {

private int skipLimit;

public void setSkipLimit(final int skipLimit) {
    this.skipLimit = skipLimit;
}

public boolean shouldSkip(final Throwable t, final int skipCount) throws SkipLimitExceededException {

    if (skipCount < this.skipLimit) {
        return true;
    }
    return false;
}
}
Run Code Online (Sandbox Code Playgroud)

因此,对于在达到跳过限制之前发生的任何错误,跳过策略将忽略该错误(返回true).达到跳过限制后,作业将因任何错误而失败.

mySkipListener类如下:

public class mySkipListener implements SkipListener<MyItem, MyItem> {

public void onSkipInProcess(final MyItem item, final Throwable t) {
    // TODO Auto-generated method stub
    System.out.println("Skipped details during PROCESS is: " + t.getMessage());
}

public void onSkipInRead(final Throwable t) {

    System.out.println("Skipped details during READ is: " + t.getMessage());
}

public void onSkipInWrite(final MyItem item, final Throwable t) {
    // TODO Auto-generated method stub
    System.out.println("Skipped details during WRITE is: " + t.getMessage());
}
}
Run Code Online (Sandbox Code Playgroud)

现在在myItemProcessor中,我有以下代码块:

if (item.getTheNumber().charAt(4) == '-') {
        item.setProductNumber(item.getTheNumber().substring(0, 3));
    } else {
        item.setProductNumber("55");
    }
Run Code Online (Sandbox Code Playgroud)

对于某些项,theNumber字段为null,因此上面的代码块会抛出"StringIndexOutofBounds"异常.

但我看到一种奇怪的行为,我不明白为什么会发生这种行为.

总共有6个项目有错误,即theNumber字段为空.

如果跳过限制大于错误数(即> 6),则跳过侦听器类中的sys out将被调用并且正在报告跳过的错误.

但是,如果跳过限制较少(比如我的示例中为5),则跳过侦听器类中的sys out根本没有被调用,而是直接在控制台上获得以下异常转储:

org.springframework.batch.retry.RetryException: Non-skippable exception in recoverer while processing; nested exception is java.lang.StringIndexOutOfBoundsException
at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor$2.recover(FaultTolerantChunkProcessor.java:282)
at org.springframework.batch.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:416)
at org.springframework.batch.retry.support.RetryTemplate.doExecute(RetryTemplate.java:285)
at org.springframework.batch.retry.support.RetryTemplate.execute(RetryTemplate.java:187)
Run Code Online (Sandbox Code Playgroud)

这种行为背后的原因是什么?我该怎么做才能解决这个问题?

谢谢阅读!

小智 2

如果包含该块的微线程正常完成,则 SkipListener 仅在该块的末尾使用。当错误数超过跳过限制时,会通过您看到的异常进行报告,并且微线程将中止。

如果错误数量小于跳过限制,则 tasklet 正常完成,并且为每个跳过的行或项目调用一次 SkipListener - Spring Batch 在运行过程中在内部构建它们的列表,但仅在最后报告。

这个想法是,如果任务失败,您可能会重试它,因此知道在不完整的运行期间跳过的内容是没有用的,每次重试时您都会收到相同的通知。只有当其他一切都成功时,您才能看到跳过的内容。想象一下您正在记录跳过的项目,您不希望将它们一次又一次地记录为跳过的项目。

正如您所看到的,简单的解决方案是使跳过限制足够大。同样的想法是,如果您必须跳过很多项目,则可能存在更严重的问题。