private <P, R> void handleResultAndEnqueueErrorHandlingAgain(final CompletionStage<R> completionStage, final Object parameter, final RetryContextImpl<P, R> retryOperationContext) { completionStage.whenCompleteAsync((res, error) -> { final boolean isErrorCase = error != null; if (isErrorCase) { final RetryContextImpl<P, R> nextContext = retryOperationContext.withNewFailedAttempt(error, parameter); handle(nextContext); } else { retryOperationContext.getResult().complete(res); } }, executor); }
RetryContextImpl<P, R> withNewFailedAttempt(final Throwable error, final Object parameter) { final long attemptCount = getAttempt() + 1; return new RetryContextImpl<>(getStartTimestamp(), attemptCount, getFirstError(), getFirstParameter(), error, parameter, getResult(), getFunction(), getService(), this::schedule); } }
private <P, R> void handle(final RetryContextImpl<P, R> retryContext) { final RetryStrategy retryStrategy = applyContext(retryContext); final StrategyType strategyType = retryStrategy.getStrategyType(); if (strategyType == StrategyType.RESUME || strategyType == StrategyType.STOP) { retryContext.getResult().completeExceptionally(retryStrategy.getError()); if (strategyType == StrategyType.STOP) { closeService(retryContext); } } else { final Function<P, CompletionStage<R>> function = retryContext.getFunction(); final Object parameter = retryStrategy.getParameter(); if (strategyType == StrategyType.RETRY_IMMEDIATELY) { retry(retryContext, function, parameter); } else if (strategyType == StrategyType.RETRY_SCHEDULED) { final Duration duration = retryStrategy.getDuration(); retryContext.schedule(() -> retry(retryContext, function, parameter), duration); } else { throw new IllegalStateException("illegal state for " + retryStrategy); } } }