Как обработать исключение FlatFileParseException от шага ведомого
У меня есть приложение Spring Batch Job, которое анализирует много CSV-файлов, содержащих данные пользователя. Для синтаксического анализа данных пользователя у меня есть LineMapper, который анализирует из CSV-файла.
Итак, сначала программа чтения основных шагов читает все файлы с места, а затем, используя Partitioner, у меня есть подчиненные шаги. Все подчиненные шаги параллельно выполняются. Эти подчиненные шаги разбирают каждый файл на предмет сведений о пользователе строка за строкой. После обработки он перемещает обработанный файл в папку "Обработано".
Во время тестирования я сохранил какое-то неправильное значение в файле, который вызывает исключение FlatFileParseException программой чтения шага. Здесь я хотел бы переместить этот файл в другую папку, например папку Failed. Но я не могу этого сделать.
Как мне записать файлы в папку Failed, если какой-либо ведомый шаговый ридер не может разобрать?
Я использую Spring Boot на основе аннотации Spring Batch
Ошибки:
FlatFileParseException: ошибка синтаксического анализа в строке: 10 в ресурсе
JobExecutionException: обработчик раздела возвратил неудачный шаг
Код:
BatchConfiguration.java
@Bean(name = "partitionerJob")
public Job partitionerJob()
throws UnexpectedInputException, MalformedURLException, ParseException {
return jobs.get("partitioningJob")
.start(partitionStep())
.build();
}
@Bean
public Step partitionStep()
throws UnexpectedInputException, MalformedURLException, ParseException {
return steps.get("partitionStep")
.partitioner("slaveStep", partitioner())
.step(slaveStep())
.taskExecutor(taskExecutor())
.build();
}
@Bean
public CustomMultiResourcePartitioner partitioner() {
CustomMultiResourcePartitioner partitioner
= new CustomMultiResourcePartitioner();
Resource[] resources;
try {
resources = resoursePatternResolver
.getResources("file:src/main/resources/input/*.csv");
} catch (IOException e) {
throw new RuntimeException("I/O problems when resolving"
+ " the input file pattern.", e);
}
partitioner.setResources(resources);
return partitioner;
}
@StepScope
@Bean
public FlatFileItemReader<Transaction> itemReader(
@Value("#{stepExecutionContext[fileName]}") String filename)
throws UnexpectedInputException, ParseException {
return new UserDetailReader(fileName);
}
@Bean
@StepScope
public ItemWriter<Transaction> itemWriter(Marshaller
marshaller ,
@Value("#{stepExecutionContext[opFileName]}") String
filename )
throws MalformedURLException {
return new UserDetailWriter(fileName);
}
@Bean
public Step slaveStep()
throws UnexpectedInputException, MalformedURLException, ParseException {
return steps.get("slaveStep").<User, User>chunk(5)
.reader(itemReader(null))
.writer(itemWriter(marshaller(), null))
.build();
}
CustomMultiResourcePartitioner.java
public class CustomMultiResourcePartitioner implements Partitioner {
@Override
public Map<String, ExecutionContext> partition(int gridSize) {
Map<String, ExecutionContext> map = new HashMap<>(gridSize);
int i = 0, k = 1;
for (Resource resource : resources) {
ExecutionContext context = new ExecutionContext();
Assert.state(resource.exists(), "Resource does not exist: "
+ resource);
context.putString(keyName, resource.getFilename());
context.putString("opFileName",
"output"+k+++".xml");
map.put(PARTITION_KEY + i, context);
i++;
}
return map;
}
}
Спасибо за помощь
1 ответ
Вы можете использовать атрибуты skip & skipLimit при определении вашего шага.
Ниже приведен пример конфигурации. Теперь ваш подчиненный шаг не завершится неудачей, пока не будет достигнут skipLimit.
@Bean
public Step slaveStep()
throws UnexpectedInputException, MalformedURLException, ParseException {
return steps.get("slaveStep").<User, User>chunk(5)
.reader(itemReader(null))
.writer(itemWriter(marshaller(), null))
.faultTolerant()
.skip(Exception.class)
.skipLimit(500)
.build();
}
Переместить файл в папку Failed
Вы можете определить StepExecutionListener для вашего slaveStep. в методе после шага вы можете получить все FailureExceptions
для этого шага. Используя это, вы можете поместить свою логику для перемещения файла
Образец кода
public class MyStepListener implements StepExecutionListener {
@Override
public void beforeStep(StepExecution stepExecution) {
LOGGER.info("MyStepListener beforeStep "+ stepExecution.getSummary());
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
List<Throwable> failureExceptions = stepExecution.getFailureExceptions();
// move file from one folder to another
return null;
}
}