我使用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写入。如果没有错误,则提交具有一个项目的迷你块,并且迭代继续下一个项目。我们期望至少有一个可跳过的异常,当发生这种情况时,事务将被回滚并且该项被标记为跳过的项。一旦我们的迭代完成,我们继续正常的块处理。
它可能是重写写操作的解释。我希望我能以某种方式绕过这种行为......
答案 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.
}
}
这并不完美,因为抛出异常的处理仍然执行了两次。但我没有两倍的日志,我的自定义错误计数是正确的。
即使我怀疑这是可行的,我仍然有兴趣采取一种方法来抑制这种“一次性通过迷你块重试”行为。