Как обработать исключение 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;
    }

}
Другие вопросы по тегам