ItemWriter 的 Spring Batch 跳过异常
Posted
技术标签:
【中文标题】ItemWriter 的 Spring Batch 跳过异常【英文标题】:Spring Batch skip exception for ItemWriter 【发布时间】:2014-04-26 16:34:41 【问题描述】:我正在尝试将 Spring Batch 2.2.5 与 Java 配置一起使用。这是我的配置:
@Configuration
@EnableBatchProcessing
public class JobConfiguration
@Autowired
private JobBuilderFactory jobBuilder;
@Autowired
private StepBuilderFactory stepBuilder;
@Bean
@Autowired
public Job processDocumentsJob()
return jobBuilder.get("processDocumentsJob")
.start(procesingStep())
.build();
@Bean
@Autowired
public Step procesingStep()
CompositeItemProcessor<File, DocumentPackageFileMetadata> compositeProcessor = new CompositeItemProcessor<File, DocumentPackageFileMetadata>();
compositeProcessor.setDelegates(Lists.newArrayList(
documentPackageFileValidationProcessor(),
documentMetadataFileTransformer()
));
return stepBuilder.get("procesingStep")
.<File, DocumentPackageFileMetadata>chunk(1)
.reader(documentPackageFileReader())
.processor(compositeProcessor)
.writer(documentMetadataFileMigrator())
.faultTolerant()
.skip(DocumentImportException.class)
.skipLimit(10)
.listener(stepExecutionListener())
.build();
....
使用上面的配置,如果 itemwriter(documentMetadataFileMigrator 指向的 bean)抛出 'DocumentImportException',则不会跳过该异常。 Spring Batch 实际上会再次重试相同的输入。即它将对“documentPackageFileValidationProcessor”使用相同的输入。
但是,如果我将 itemwriter 内部的逻辑移动到 itemprocessor 中:
@Bean
@Autowired
public Step procesingStep()
CompositeItemProcessor<File, DocumentPackageFileMetadata> compositeProcessor = new CompositeItemProcessor<File, DocumentPackageFileMetadata>();
compositeProcessor.setDelegates(Lists.newArrayList(
documentPackageFileValidationProcessor(),
documentMetadataFileTransformer(),
documentMetadataFileMigratorAsProcessor() // same as itemwriter, but implemented as itemprocessor
));
return stepBuilder.get("procesingStep")
.<File, DocumentPackageFileMetadata>chunk(1)
.reader(documentPackageFileReader())
.processor(compositeProcessor)
.faultTolerant()
.skip(DocumentImportException.class)
.skipLimit(10)
.listener(stepExecutionListener())
.build();
那么异常将被正确跳过。即 Spring Batch 不会针对“documentPackageFileValidationProcessor”重试相同的项目。它将转到下一个要处理的项目(从“documentPackageFileReader”返回的项目)。
这是 Spring Batch 上的错误,还是按预期运行?如果是这样,有人可以指点我相关的文档吗?
谢谢大家,如果这是一个基本问题,我们深表歉意。
最好的问候,
亚历克斯
【问题讨论】:
【参考方案1】:这种行为是正确的。 ItemWriter 接收要写入的项目列表。如果抛出可跳过的异常,Spring Batch 会尝试确定哪个项目实际导致了异常,因此仅跳过该项目。这样做的方法是回滚事务,将提交间隔更改为 1,然后重新处理每个项目并再次尝试写入。这仅允许跳过有错误的项目,而不需要跳过整个块。
这里讨论了同样的问题(仅使用 XML 配置):How is the skipping implemented in Spring Batch?
【讨论】:
嗨,迈克尔。谢谢回复。我看到的情况如下:假设有 3 项,第 1 项会导致写入失败。由于异常,第一次写入将停止,当然,其余项目不会被写入。然后 Spring 尝试再次写入(如您所说),但包含所有项目(包括项目 1)。这将再次导致失败。就是这样。没有尝试写第 2 项和第 3 项 我刚刚再次浏览了该应用程序。我现在知道为什么它没有处理其余的项目。这是因为在重试期间,其中一个 itemprocessor 抛出了一个不可跳过的异常。傻我!感谢伟大的指针,迈克尔 其实……再想一想——如果块大小为1,那么它不应该需要返回并再次重试整个链来确定哪个项目导致错误,对吧?我的意思是...如果块大小为 1,并且配置是跳过异常,则不重试该异常...然后继续处理下一项。 ItemWriter#write 方法接收项目列表。如果不一次遍历它们,我们就无法确定列表中的哪个在编写器中引发了异常。框架所知道的就是该列表中的某些内容导致某些内容中断。 对我来说,它的行为有点不同。说,我有 4 条记录要读取 - 处理 - 写入,块大小为 10。Record-2 有一些问题,它在“进程”状态期间引发可跳过的异常。它正确地跳过它,但只写入 Record-3 和 Record-4。被正确读取和处理的 Record-1 根本没有被写入。有什么问题?【参考方案2】:最后,这对我有用 - 如果我想使用 itemwriter,而不需要对同一项目进行重新处理:
@Bean
@Autowired
public Step procesingStep()
CompositeItemProcessor<DocumentPackageFileMetadata, DocumentPackageFileMetadata> compositeProcessor = new CompositeItemProcessor<DocumentPackageFileMetadata, DocumentPackageFileMetadata>();
compositeProcessor.setDelegates(Lists.newArrayList(
documentPackageFileValidationProcessor(),
documentPackageFileExtractionProcessor(),
documentMetadataFileTransformer()
));
return stepBuilder.get("procesingStep")
.<DocumentPackageFileMetadata, DocumentPackageFileMetadata>chunk(1)
.reader(documentPackageFileReader())
.processor(compositeProcessor)
.writer(documentMetadataFileMigrator())
.faultTolerant()
.skip(DocumentImportException.class)
.noRetry(DocumentImportException.class)
.noRollback(DocumentImportException.class)
.skipLimit(10)
.listener(skipListener())
.listener(documentPackageReadyForProcessingListener())
.listener(stepExecutionListener())
.build();
请注意,我已指定“noRetry”和“noRollback”。
【讨论】:
不适合我,它仍然会再次重试该块,即使使用 noRetry 和 noRollBack,也会导致同一记录出现 2 个错误日志。 @CristianoFontes 我知道这已经有一段时间了,但你找到解决办法了吗?以上是关于ItemWriter 的 Spring Batch 跳过异常的主要内容,如果未能解决你的问题,请参考以下文章
Spring Batch @EnableBatchIntegration 注解
Spring Batch:根据 itemReader 中的结果执行作业