Configurando ignorar lógica no lote em primavera
1. Introdução
Por padrão, qualquer erro encontrado durante o processamento de um trabalhoSpring Batch fará com que uma etapa correspondente falhe. No entanto, existem muitas situações em que preferimos ignorar o item atualmente processado para certas exceções.
Neste tutorial,we’ll explore two approaches to configure skip logic in the Spring Batch framework.
2. Nosso Caso de Uso
Para fins de exemplos,we’ll reuse a simple, chunk-oriented job presented already in our Spring Batch introductory article.
Este trabalho converte alguns dados financeiros de um formato CSV para XML.
2.1. Dados de entrada
Primeiro, vamos adicionar algumas linhas ao arquivo CSV original:
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
Como podemos ver, as últimas três linhas contêm alguns dados inválidos - as linhas 5 e 7 estão ausentes do campo de nome de usuário e o valor da transação na linha 6 é negativo.
Nas seções posteriores, configuraremos nosso trabalho em lote para ignorar esses registros corrompidos.
3. Configurando limites de ignição e exceções ignoráveis
3.1. Usandoskip eskipLimit
Vamos agora discutir a primeira das duas maneiras de configurar nosso trabalho para pular itens em caso de falha - os métodosskipeskipLimit:
@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();
}
Primeiro de tudo,to enable skip functionality, we need to include a call to faultTolerant() during the step-building process.
Dentro deskip()eskipLimit(), definimos as exceções que queremos ignorar e o número máximo de itens ignorados.
No exemplo acima, seMissingUsernameException ouNegativeAmountException for lançado durante a fase de leitura, processo ou gravação, o item atualmente processado será omitido e contado em relação ao limite total de dois.
Consequentemente,if any exception is thrown a third time, then the whole step will fail.
3.1. UsandonoSkip
No exemplo anterior, qualquer outra exceção além deMissingUsernameExceptioneNegativeAmountException fará com que nossa etapa falhe.
Em algumas situações, no entanto, pode ser mais apropriado paraidentify exceptions that should make our step fail and skip on any other.
Vamos ver como podemos configurar isso usandoskip,skipLimit enoSkip:
@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();
}
Com a configuração acima, instruímos o framework Spring Batch a pular em qualquerException (dentro de um limite configurado), excetoSAXException. This means SAXException always causes a step failure.
A ordem das chamadasskip()enoSkip() não importa.
4. UsandoSkipPolicy personalizado
Às vezes, podemos precisar de um mecanismo de verificação de salto mais sofisticado. Para esse propósito,Spring Batch framework provides the SkipPolicy interface.
Podemos então fornecer nossa própria implementação de ignorar lógica e conectá-la à nossa definição de etapa.
Mantendo o exemplo anterior em mente, imagine que ainda queremos definir um limite de salto de dois itens e tornar apenasMissingUsernameExceptioneNegativeAmountException puláveis.
No entanto,an additional constraint is that we can skip NegativeAmountException, but only if the amount doesn’t exceed a defined limit.
Vamos implementar nossoSkipPolicy personalizado:
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;
}
}
Agora, podemos usar nossa política personalizada em uma definição de etapa:
@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();
}
E, de forma semelhante ao nosso exemplo anterior, ainda precisamos usarfaultTolerant() para ativar a funcionalidade de pular.
Desta vez, entretanto, não chamamosskip() ounoSkip(). Em vez disso,we use the skipPolicy()method to provide our own implementation of the SkipPolicyinterface.
Como podemos ver,this approach gives us more flexibility, so it can be a good choice in certain use cases.
5. Conclusão
Neste tutorial, apresentamos duas maneiras de tornar um trabalho do Spring Batch tolerante a falhas.
Embora o uso deskipLimit() junto com os métodosskip()enoSkip() pareça ser mais popular, podemos achar que implementar umSkipPolicy personalizado é mais conveniente em algumas situações.
Como de costume, todos os exemplos de código estão disponíveisover on GitHub.