Spring Batch使用Spring Boot - 永远不要重写写入错误

时间:2016-02-22 16:25:28

标签: java spring spring-boot spring-batch

我使用Spring Boot创建了一个批处理。以下是批处理的主要配置类:

@Configuration
@EntityScan({"my.domain"})
@EnableJpaRepositories({"my.domain"})
@EnableBatchProcessing
public class BatchConfiguration {

    /** Motif d'identification des fichiers d'entrée */
    @Value("${batch.input-file-pattern}")
    private String inputFilePattern;

    @Bean
    public BatchConfigurer configurer( EntityManagerFactory entityManagerFactory ){ 
        return new MapForcedBatchConfigurer( entityManagerFactory ); 
    }

    @Bean
    public Job myJob( JobBuilderFactory jobs, Step step1 ){
        return jobs.get("myJob")
                .incrementer( new RunIdIncrementer() )
                .flow( step1 )
                .end()
                .build();
    }

    @Bean
    public Step step1( StepBuilderFactory stepBuilderFactory, 
            StepExecutionListener stepExecutionListener,
            ItemReader<Input> myReader,
            ItemProcessor<Input, Dto> myProcessor, 
            ItemWriter<Dto> myWriter ){
        return stepBuilderFactory.get("myStep")
                .listener( stepExecutionListener )
                .<Input, Dto> chunk(1)
                .reader( myReader )
                .processor( myProcessor )
                .writer( myWriter )
                .faultTolerant().skipPolicy( new MySkipPolicy() ).retryLimit( 0 )
                .build();
    }

    @Bean
    public StepExecutionListener stepListener() {
        return new MyStepExecutionListener();
    }

    @Bean
    public ItemReader<Input> myReader() throws IOException {
        return new MyItemReader( inputFilePattern );
    }

    @Bean
    public ItemProcessor<Input, Dto> myProcessor(){
        return new MyItemProcessor();
    }

    @Bean
    public ItemWriter<Dto> myWriter(){
        return new MyItemWriter();
    }

}

处理项目发生错误时,记录器会编写一条消息,然后批处理下一个元素。这正是我想要的。

但是当写入项目发生错误时,批处理总是会重试该操作一次!因此,每次写入错误都有2个错误日志。

如何将错误配置为永远不会重试,无论错误发生在哪个步骤?

This article解释了以下内容:

  

[当我们在写作期间跳过]时,框架必须找出导致失败的项目。对于已读取项目的缓存列表中的每个项目,它将启动自己的事务。该项由ItemProcessor处理,然后由ItemWriter写入。如果没有错误,则提交具有一个项目的迷你块,并且迭代继续下一个项目。我们期望至少有一个可跳过的异常,当发生这种情况时,事务将被回滚并且该项被标记为跳过的项。一旦我们的迭代完成,我们继续正常的块处理。

它可能是重写写操作的解释。我希望我能以某种方式绕过这种行为......

2 个答案:

答案 0 :(得分:1)

我认为如果没有子类化FaultTolerantChunkProcessor,你就无法做到。在步骤构建器上调用readerIsTransactionalQueue()强制执行您想要的行为,但它会忽略所有异常(不会调用您的跳过策略)。

原因是Spring Batch尝试确定导致错误的项目,即使你的块只有一个项目,算法也不考虑它(事实上,为什么你使用大小为1的块? ...)

您可以做的是在作家中自己捕捉异常。你甚至可以为这个唯一目的写一个包裹ItemWriter

答案 1 :(得分:1)

我终于提出了一个非常简单的解决方法。我在标记为@OnSkipInWrite的方法中出现错误时移动了日志和操作。因此,当Spring Batch最终跳过导致错误的元素时,此代码仅执行一次。

public class MyItemWriter implements ItemWriter<Dto> {

    @Override
    public void write(List<? extends Dto> items) throws Exception {
        // The writing treatment which may throw a skippable exception...
    }

    @OnSkipInWrite
    public void onSkipInWrite( Dto skippedItem, Exception exception ){
        // Logs, counters, etc.
    }

}

这并不完美,因为抛出异常的处理仍然执行了两次。但我没有两倍的日志,我的自定义错误计数是正确的。

即使我怀疑这是可行的,我仍然有兴趣采取一种方法来抑制这种“一次性通过迷你块重试”行为。