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); } }
public RetryContextImpl(final Instant startTimestamp, final Long attempt, final Throwable firstError, final Object firstParameter, final Throwable latestError, final Object latestParameter, final CompletableFuture<R> result, final Function<P, CompletionStage<R>> f, final AutoCloseable closeable, final BiConsumer<Runnable, Duration> scheduler) { this.attempt = attempt; this.startTimestamp = startTimestamp; this.firstError = filterOutCompletionException(firstError); this.latestError = filterOutCompletionException(latestError); this.firstParameter = firstParameter; this.latestParameter = latestParameter; this.result = result; this.f = f; this.closeable = closeable; this.scheduler = scheduler; }
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); } } }
private <P, R> RetryContextImpl<P, R> createFirstRetryOperationContext(final Throwable throwable, final CompletableFuture<R> result, final Function<P, CompletionStage<R>> f, final P parameterObject, final AutoCloseable service) { final long attemptCount = 1L; final Instant now = Instant.now(); return new RetryContextImpl<>(now, attemptCount, throwable, parameterObject, throwable, parameterObject, result, f, service, this::schedule); }
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); }
private <P, R> void closeService(final RetryContextImpl<P, R> retryContext) { try { retryContext.getService().close(); } catch (final Exception e) { logger.error("Error occurred while closing service in retry strategy.", e); } }
private RetryContextImpl<Object, Object> getRetryContext(final Throwable latestError) { return new RetryContextImpl<>(null, null, null, null, latestError, null, null, null, null, null); } }