Spring Batch依赖资源不可用时的记录拒斥与重处理方案咨询
Spring Batch中依赖资源不可用时的记录拒斥与自动重处理方案
问题背景
当记录依赖的外部资源(比如某文件记录关联的PDF文件,该PDF由外部任务后续推送)不可用时,如何在Spring Batch中实现记录拒斥及后续自动重处理?目前我们考虑了以下三个方向:
- 方案1:在Reader阶段校验PDF是否存在
- 方案2:在Processor阶段校验PDF是否存在,若不存在则返回Null以触发重处理
- 方案3:是否有其他更合适的替代方案?
已尝试的代码实现
Reader 代码片段
fileScannerDTO.setPdfFileNotExist(!Files.exists(Paths.get(fileScannerDTO.getFilePath())));
Processor 代码片段
if(fileScannerDTO.isPdfFileNotExist()) { return null; }
方案分析与优化建议
Reader阶段校验的局限性
在Reader里直接校验资源存在性,若资源不存在就跳过记录的话,会导致这条记录直接被排除在批处理流程外,后续无法自动重处理——因为Reader已经跳过了它,除非额外把这些未处理的记录持久化到重试队列,否则批处理结束后无法触发二次处理。Processor返回Null的问题
Processor返回Null确实会让Spring Batch跳过当前记录,但默认情况下这些跳过的记录不会被自动重试。如果要实现自动重处理,需要结合重试机制和跳过策略,同时把未处理的记录持久化到专门的待重试表中,后续通过定时任务重新触发批处理。
推荐的替代方案:跳过策略+重试机制+持久化待重试记录
更稳健的实现方式分为四步:
- 定义自定义异常:创建
MissingDependencyResourceException,检测到PDF不存在时抛出该异常,而非返回Null - 配置跳过策略:在Job配置中设置跳过该自定义异常,同时通过
SkipListener将跳过的记录信息持久化到数据库待重试表 - 配置重试机制:为Processor阶段配置重试规则,设置重试次数和间隔,重试失败后再触发跳过并持久化
- 定时任务重处理:编写定时任务,定期扫描待重试表,将已满足资源条件的记录重新导入批处理流程
示例代码片段
自定义异常
public class MissingDependencyResourceException extends RuntimeException { public MissingDependencyResourceException(String message) { super(message); } }
Processor中抛出异常
@Override public FileScannerDTO process(FileScannerDTO item) throws Exception { if (!Files.exists(Paths.get(item.getFilePath()))) { throw new MissingDependencyResourceException("PDF文件不存在:" + item.getFilePath()); } // 正常处理逻辑 return item; }
Job配置中的跳过与重试配置
@Bean public Step myStep(StepBuilderFactory stepBuilderFactory, ItemReader<FileScannerDTO> reader, ItemProcessor<FileScannerDTO, FileScannerDTO> processor, ItemWriter<FileScannerDTO> writer, SkipListener<FileScannerDTO, FileScannerDTO> skipListener) { return stepBuilderFactory.get("myStep") .<FileScannerDTO, FileScannerDTO>chunk(10) .reader(reader) .processor(processor) .writer(writer) .faultTolerant() .skip(MissingDependencyResourceException.class) .skipLimit(Integer.MAX_VALUE) // 根据实际需求设置跳过上限 .retry(MissingDependencyResourceException.class) .retryLimit(3) // 重试3次 .listener(skipListener) .build(); }
SkipListener实现持久化待重试记录
@Component public class MySkipListener implements SkipListener<FileScannerDTO, FileScannerDTO> { @Autowired private RetryRecordRepository retryRecordRepository; @Override public void onSkipInProcess(FileScannerDTO item, Throwable t) { if (t instanceof MissingDependencyResourceException) { RetryRecord record = new RetryRecord(); record.setItemId(item.getId()); record.setItemType("FILE_SCANNER"); record.setReason(t.getMessage()); record.setRetryStatus("PENDING"); retryRecordRepository.save(record); } } // 其他Skip方法按需实现 }
内容的提问来源于stack exchange,提问作者Rakesh
相关产品推荐
相关产品推荐

