Как я могу выполнить логику восстановления при каждой попытке с помощью Spring RetryTemplate - PullRequest
0 голосов
/ 19 июня 2019

У меня есть пружинный RetryTemplate, оборачивающий набор вызовов http в службу обертывания БД, которая при объединении имеет весь транзакционный характер, что означает, что в случае сбоя последнего из них мне нужно откатить все ранее выполненные операции и начать обработку все кончено.

Проблема в том, что восстановление выполняется только после последней попытки сбоя, что делает проблему больше, чем я пытался решить:

У меня есть состояние БД, несовместимое между каждой попыткой.

Как мне выполнить восстановление после каждой неудачной попытки?

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

//I'm only experimenting now, when I'm done the template and policy will be injected.
RetryTemplate relshpProcessRetry = new RetryTemplate();
    SimpleRetryPolicy retryPolicy=new SimpleRetryPolicy();
    retryPolicy.setMaxAttempts(3);
    relshpProcessRetry.setRetryPolicy(retryPolicy);
    try {
      relshpProcessRetry
          .execute((RetryCallback<Void, StorageAccessorException>) context -> {
            final var decisions = decideRelationships(relationshipRequest).getDecisions();
            context
                .setAttribute(String.valueOf(relationshipRequest.getParentListingId()), decisions);
            decisions
                .forEach(relationshipDecision -> relationshipDecision.apply(storageAccessor));
            return null;
          }, context -> {
            //noinspection unchecked
            List<RelationshipDecision> decisions = (List<RelationshipDecision>) context
                .getAttribute(String.valueOf(relationshipRequest.getParentListingId()));

            //noinspection ConstantConditions
            Validate.notEmpty(decisions, "Decisions to rollback must not be null");
            ReverseListIterator<RelationshipDecision> decisionReverseIterator = new ReverseListIterator<>(
                decisions);
            while (decisionReverseIterator.hasNext()) {
              final var decision = decisionReverseIterator.next();
              if (decision.isApplied()) {
                decision.rollback(storageAccessor);
              }
            }
            return null;
          });
    } catch (ExhaustedRetryException e) {
      //if we are here, all attempts ended in optimistic lock exceptions
      log.debug(
          "Failed to process relationship(s) for request {} , after all retry attempts have been exhausted",
          relationshipRequest, e);
      throw new IllegalStateException(
          "Relationship processing failed - " + relationshipRequest.toString(), e);
    }

В моих модульных тестах я вижу следующее, напечатанное до первого восстановления:

14:24:38.882 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=0
14:24:40.726 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=1
14:24:40.726 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=1
14:24:41.843 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=2
14:24:41.843 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=2
14:24:42.781 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=3
14:24:42.781 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry failed last attempt: count=3

1 Ответ

0 голосов
/ 19 июня 2019

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

...