Автор оригинала: 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( ItemProcessorprocessor, 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( ItemProcessorprocessor, 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( ItemProcessorprocessor, 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 .