Повторить не работает, когда откат управляемой транзакции Spring Batch - PullRequest
0 голосов
/ 22 апреля 2020

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

  @Bean
  public Step myStep(StaxEventItemReader<Response> staxEventResponseReader,
      ItemWriter<Response> itemWriter,
      ItemProcessor<? super Response, ? extends Response> responseProcessor) {
    return stepBuilderFactory.get("myStep")
        .<Response, Response>chunk(1)
        .reader(staxEventResponseReader)
        .processor(responseProcessor)
        .writer(itemWriter)
        //.faultTolerant().retryLimit(3).retry(Exception.class)
        .build();
  }

Логика c модуля записи для этого шага довольно проста: он пытается прочитать строку из базы данных и, как только находит строку, обновляет ее. Я смог воспроизвести ObjectOptimisticLockingFailureException, установив точку останова сразу после метода поиска, вручную поднял столбец version для строки в базе данных и зафиксировал ее, а затем возобновил.

Однако после раскомментирования повторной попытки определение в моем шаге, попытки не были предприняты. После некоторой отладки кажется, что Spring retry logi c находится внутри транзакции чанка; но, поскольку ObjectOptimisticLockingFailureException не генерируется моим кодом в модуле записи, а из-за транзакции фрагмента Spring, фиксирующей logi c, попытки вообще не предпринимались.

Chunk Transaction Begin
    Begin Retry loop in FaultTolerantChunkProcessor.write()
        Writer logic in my Step
    End Retry loop
Chunk Transaction Commit - Throws ObjectOptimisticLockingFailureException

Когда я пытался явно выбросить ObjectOptimisticLockingFailureException в моем писателе лог повторов c работал отлично, как и ожидалось. Мои вопросы:

  1. Как заставить работать лог повторов c, если исключение не генерируется из кода моего модуля записи на шаге, но к тому времени, когда транзакция порции фиксируется Spring Batch?
  2. Другое странное поведение заключается в том, что, когда я вручную вызываю ObjectOptimisticLockingFailureException, поднимая столбец версии в базе данных, с определением повторения, прокомментированным в шаге, конечный статус шага НЕУДАЧЕН, что ожидается. Но если определение повторной попытки не закомментировано, окончательный статус шага ЗАВЕРШЕН. Почему это?

1 Ответ

1 голос
/ 23 апреля 2020
  1. Как заставить протокол повторных попыток c работать, если исключение не генерируется из кода моего модуля записи в шаге, но к тому времени, когда транзакция порции фиксируется Spring Batch?

Здесь есть открытый вопрос: https://github.com/spring-projects/spring-batch/issues/1826. Обходной путь должен (попытаться предвидеть и) выбросить любое исключение, которое может произойти во время фиксации в авторе. Это то, что вы уже попробовали и подтвердили, что работает, когда вы говорите When I tried to explicitly throw ObjectOptimisticLockingFailureException in my writer, the retry logic worked perfectly as expected.

Другое странное поведение заключается в том, что когда я вручную вызываю исключение ObjectOptimisticLockingFailureException, увеличивая столбец версии в базе данных, с определением повторения, прокомментированным на шаге, конечный статус шага НЕУДАЧЕН, что ожидается. Но если определение повторной попытки не закомментировано, окончательный статус шага ЗАВЕРШЕН. Почему это так?

Это связано с предыдущей проблемой, но вызвано другой: https://github.com/spring-projects/spring-batch/issues/1189. Тем не менее, можно поиграть с полем version во время сеанса отладки, чтобы понять, как все это работает, но я бы не рекомендовал изменить столбец version в вашем коде. Spring Batch полагается на этот столбец в своей оптимизированной стратегии блокировки c, и не ожидается, что он изменит значения этого столбца в коде пользователя, иначе может произойти непредвиденное поведение.

...