Рубрики
Без рубрики

Настройка логики пропуска в пакете Spring

Краткий и практический обзор настройки логики пропуска в пакете Spring.

Автор оригинала: Krzysztof Woyke.

1. введение

По умолчанию любые ошибки, возникшие во время обработки задания Spring Batch , приведут к сбою соответствующего шага. Однако есть много ситуаций, в которых мы предпочли бы пропустить обрабатываемый в данный момент элемент для определенных исключений.

В этом уроке мы рассмотрим два подхода к настройке логики пропуска в Spring Batch framework.

2. Наш Пример Использования

Для целей примеров мы повторно используем простую, ориентированную на фрагменты работу, представленную уже в нашей вводной статье Spring Batch|/.

Это задание преобразует некоторые финансовые данные из формата CSV в формат XML.

2.1. Входные данные

Во-первых, давайте добавим несколько строк в исходный CSV-файл:

username, user_id, transaction_date, transaction_amount
devendra, 1234, 31/10/2015, 10000
john, 2134, 3/12/2015, 12321
robin, 2134, 2/02/2015, 23411
, 2536, 3/10/2019, 100
mike, 9876, 5/11/2018, -500
, 3425, 10/10/2017, 9999

Как мы видим, последние три строки содержат некоторые недопустимые данные – в строках 5 и 7 отсутствует поле имени пользователя, а сумма транзакции в строке 6 отрицательна.

В последующих разделах мы настроим наше пакетное задание, чтобы пропустить эти поврежденные записи.

3. Настройка ограничения пропуска и пропускаемых исключений

3.1. Использование пропусков и лимитов пропусков

Теперь давайте обсудим первый из двух способов настройки нашего задания на пропуск элементов в случае сбоя — методы skip и skipLimit :

@Bean
public Step skippingStep(
  ItemProcessor processor,
  ItemWriter writer) throws ParseException {
    return stepBuilderFactory
      .get("skippingStep")
      .chunk(10)
      .reader(itemReader(invalidInputCsv))
      .processor(processor)
      .writer(writer)
      .faultTolerant()
      .skipLimit(2)
      .skip(MissingUsernameException.class)
      .skip(NegativeAmountException.class)
      .build();
}

Прежде всего, чтобы включить функцию пропуска, нам нужно включить вызов fault Tolerant() во время процесса пошагового построения.

В skip() и skip Limit () мы определяем исключения , которые мы хотим пропустить, и максимальное количество пропущенных элементов.

В приведенном выше примере, если во время фазы чтения, обработки или записи возникнет исключение Отсутствующее имя пользователя или NegativeAmountException , то обрабатываемый в данный момент элемент будет опущен и засчитан по общему ограничению в два.

Следовательно, если какое-либо исключение будет вызвано в третий раз, то весь шаг завершится ошибкой .

3.1. Использование noSkip

В предыдущем примере любое другое исключение, кроме Отсутствующего исключения имени пользователя и NegativeAmountException , приводит к сбою нашего шага.

Однако в некоторых ситуациях может быть более уместно определить исключения, которые должны привести к сбою нашего шага и пропустить любой другой.

Давайте посмотрим, как мы можем настроить это с помощью skip , skip Limit и no Skip :

@Bean
public Step skippingStep(
  ItemProcessor processor,
  ItemWriter writer) throws ParseException {
    return stepBuilderFactory
      .get("skippingStep")
      .chunk(10)
      .reader(itemReader(invalidInputCsv))
      .processor(processor)
      .writer(writer)
      .faultTolerant()
      .skipLimit(2)
      .skip(Exception.class)
      .noSkip(SAXException.class)
      .build();
}

В приведенной выше конфигурации мы инструктируем Spring Batch framework пропустить любое Исключение (в пределах заданного предела), кроме SAXException . Это означает, что SAXException всегда вызывает сбой шага.

Порядок вызовов skip() и no Skip() не имеет значения.

4. Использование Пользовательской Политики Пропуска

Иногда нам может понадобиться более сложный механизм проверки пропусков. Для этой цели/| Spring Batch framework предоставляет интерфейс Skip Policy|/.

Затем мы можем предоставить нашу собственную реализацию логики пропуска и подключить ее к нашему определению шага.

Имея в виду предыдущий пример, представьте, что мы все еще хотим определить ограничение на пропуск двух элементов и сделать пропускаемыми только MissingUsernameException и NegativeAmountException .

Однако дополнительным ограничением является то, что мы можем пропустить NegativeAmountException, но только в том случае, если сумма не превышает определенного предела .

Давайте реализуем нашу пользовательскую Политику пропуска :

public class CustomSkipPolicy implements SkipPolicy {

    private static final int MAX_SKIP_COUNT = 2;
    private static final int INVALID_TX_AMOUNT_LIMIT = -1000;

    @Override
    public boolean shouldSkip(Throwable throwable, int skipCount) 
      throws SkipLimitExceededException {

        if (throwable instanceof MissingUsernameException && skipCount < MAX_SKIP_COUNT) {
            return true;
        }

        if (throwable instanceof NegativeAmountException && skipCount < MAX_SKIP_COUNT ) {
            NegativeAmountException ex = (NegativeAmountException) throwable;
            if(ex.getAmount() < INVALID_TX_AMOUNT_LIMIT) {
                return false;
            } else {
                return true;
            }
        }

        return false;
    }
}

Теперь мы можем использовать нашу пользовательскую политику в определении шага:

    @Bean
    public Step skippingStep(
      ItemProcessor processor,
      ItemWriter writer) throws ParseException {
        return stepBuilderFactory
          .get("skippingStep")
          .chunk(10)
          .reader(itemReader(invalidInputCsv))
          .processor(processor)
          .writer(writer)
          .faultTolerant()
          .skipPolicy(new CustomSkipPolicy())
          .build();
    }

И, как и в нашем предыдущем примере, нам все еще нужно использовать fault Tolerant () , чтобы включить функцию пропуска.

На этот раз, однако, мы не вызываем skip() или no Skip() . Вместо этого мы используем метод skip Policy() для обеспечения собственной реализации интерфейса Skip Policy .

Как мы видим, этот подход дает нам большую гибкость, поэтому он может быть хорошим выбором в определенных случаях использования .

5. Заключение

В этом руководстве мы представили два способа сделать пакетное задание Spring отказоустойчивым.

Несмотря на то, что использование skip Limit() вместе с skip() и skip() методами кажется более популярным, мы можем найти реализацию пользовательского SkipPolicy более удобной в некоторых ситуациях.

Как обычно, все примеры кода доступны на GitHub .