
io.vrap.rmf.base.client.http.RetryMiddleware Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rmf-java-base Show documentation
Show all versions of rmf-java-base Show documentation
The e-commerce SDK from commercetools for Java
package io.vrap.rmf.base.client.http;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Function;
import io.vrap.rmf.base.client.*;
import io.vrap.rmf.base.client.utils.json.JsonException;
import io.vrap.rmf.base.client.utils.json.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.failsafe.Failsafe;
import dev.failsafe.FailsafeExecutor;
import dev.failsafe.RetryPolicy;
import dev.failsafe.event.ExecutionAttemptedEvent;
import dev.failsafe.spi.Scheduler;
/**
* Implementation for a retry of a requests upon configured response status codes
*/
public class RetryMiddleware implements RetryRequestMiddleware, AutoCloseable {
static final String loggerName = ClientBuilder.COMMERCETOOLS + ".retry";
/**
* @deprecated use {@link RetryRequestMiddleware#DEFAULT_MAX_DELAY} instead
*/
@Deprecated
public static final int DEFAULT_MAX_DELAY = RetryRequestMiddleware.DEFAULT_MAX_DELAY;
/**
* @deprecated use {@link RetryRequestMiddleware#DEFAULT_INITIAL_DELAY} instead
*/
@Deprecated
public static final int DEFAULT_INITIAL_DELAY = RetryRequestMiddleware.DEFAULT_INITIAL_DELAY;
/**
* @deprecated use {@link RetryRequestMiddleware#DEFAULT_RETRY_STATUS_CODES} instead
*/
@Deprecated
public static final List DEFAULT_RETRY_STATUS_CODES = RetryRequestMiddleware.DEFAULT_RETRY_STATUS_CODES;
private static final InternalLogger logger = InternalLogger.getLogger(loggerName);
private static final Logger classLogger = LoggerFactory.getLogger(RetryMiddleware.class);
private final FailsafeExecutor> failsafeExecutor;
/**
* @deprecated use {@link RetryRequestMiddleware#of(int)} instead
* @param maxRetries number of retries before giving up
*/
@Deprecated
public RetryMiddleware(final int maxRetries) {
this(Scheduler.DEFAULT, maxRetries, RetryRequestMiddleware.DEFAULT_INITIAL_DELAY,
RetryRequestMiddleware.DEFAULT_MAX_DELAY, RetryRequestMiddleware.DEFAULT_RETRY_STATUS_CODES, null);
}
/**
* @deprecated use {@link RetryRequestMiddleware#of(int, List)} instead
* @param maxRetries number of retries before giving up
* @param statusCodes response status codes to be retried
*/
@Deprecated
public RetryMiddleware(final int maxRetries, final List statusCodes) {
this(Scheduler.DEFAULT, maxRetries, RetryRequestMiddleware.DEFAULT_INITIAL_DELAY,
RetryRequestMiddleware.DEFAULT_MAX_DELAY, statusCodes, null);
}
RetryMiddleware(final int maxRetries, final List statusCodes,
final List> failures) {
this(Scheduler.DEFAULT, maxRetries, RetryRequestMiddleware.DEFAULT_INITIAL_DELAY,
RetryRequestMiddleware.DEFAULT_MAX_DELAY, statusCodes, failures);
}
/**
* @deprecated use {@link RetryRequestMiddleware#of(int, long, long)} instead
* @param maxRetries number of retries before giving up
* @param delay initial delay before retry
* @param maxDelay maximum delay before retry
*/
@Deprecated
public RetryMiddleware(final int maxRetries, final long delay, final long maxDelay) {
this(Scheduler.DEFAULT, maxRetries, delay, maxDelay, RetryRequestMiddleware.DEFAULT_RETRY_STATUS_CODES, null);
}
/**
* @deprecated use {@link RetryRequestMiddleware#of(int, long, long, List)} instead
* @param maxRetries number of retries before giving up
* @param delay initial delay before retry
* @param maxDelay maximum delay before retry
* @param statusCodes response status codes to be retried
*/
@Deprecated
public RetryMiddleware(final int maxRetries, final long delay, final long maxDelay,
final List statusCodes) {
this(Scheduler.DEFAULT, maxRetries, delay, maxDelay, statusCodes, null);
}
RetryMiddleware(final int maxRetries, final long delay, final long maxDelay, final List statusCodes,
final List> failures) {
this(Scheduler.DEFAULT, maxRetries, delay, maxDelay, RetryRequestMiddleware.handleFailures(failures)
.andThen(RetryRequestMiddleware.handleStatusCodes(statusCodes)));
}
RetryMiddleware(final ExecutorService executorService, final int maxRetries, final long delay, final long maxDelay,
final List statusCodes, final List> failures) {
this(executorService, maxRetries, delay, maxDelay, RetryRequestMiddleware.handleFailures(failures)
.andThen(RetryRequestMiddleware.handleStatusCodes(statusCodes)));
}
RetryMiddleware(final ScheduledExecutorService executorService, final int maxRetries, final long delay,
final long maxDelay, final List statusCodes, final List> failures) {
this(executorService, maxRetries, delay, maxDelay, RetryRequestMiddleware.handleFailures(failures)
.andThen(RetryRequestMiddleware.handleStatusCodes(statusCodes)));
}
RetryMiddleware(final Scheduler scheduler, final int maxRetries, final long delay, final long maxDelay,
final List statusCodes, final List> failures) {
this(scheduler, maxRetries, delay, maxDelay, RetryRequestMiddleware.handleFailures(failures)
.andThen(RetryRequestMiddleware.handleStatusCodes(statusCodes)));
}
RetryMiddleware(final int maxRetries, final long delay, final long maxDelay,
final FailsafeRetryPolicyBuilderOptions fn) {
this(Scheduler.DEFAULT, maxRetries, delay, maxDelay, fn);
}
RetryMiddleware(final ExecutorService executorService, final int maxRetries, final long delay, final long maxDelay,
final FailsafeRetryPolicyBuilderOptions fn) {
this(Scheduler.of(executorService), maxRetries, delay, maxDelay, fn);
}
RetryMiddleware(final ScheduledExecutorService executorService, final int maxRetries, final long delay,
final long maxDelay, final FailsafeRetryPolicyBuilderOptions fn) {
this(Scheduler.of(executorService), maxRetries, delay, maxDelay, fn);
}
RetryMiddleware(final Scheduler scheduler, final int maxRetries, final long delay, final long maxDelay,
final FailsafeRetryPolicyBuilderOptions fn) {
RetryPolicy> retryPolicy = fn
.apply(RetryPolicy.> builder()
.withBackoff(delay, maxDelay, ChronoUnit.MILLIS)
.withJitter(0.25)
.withMaxRetries(maxRetries)
.onRetry(this::logEventFailure))
.build();
this.failsafeExecutor = Failsafe.with(retryPolicy).with(scheduler);
}
private void logEventFailure(ExecutionAttemptedEvent> event) {
final int attempt = event.getAttemptCount();
logger.info(() -> "Retry #" + attempt);
logger.trace(() -> {
final Throwable failure = event.getLastException();
if (failure instanceof ApiHttpException) {
final ApiHttpException httpException = (ApiHttpException) failure;
final ApiHttpRequest request = httpException.getRequest();
final ApiHttpResponse response = httpException.getResponse();
if (request != null) {
return requestLog(attempt, request, response);
}
}
return event.toString();
});
}
private String requestLog(final int attempt, ApiHttpRequest request, ApiHttpResponse> response) {
String output;
final String httpMethodAndUrl = request.getMethod().name() + " " + request.getUrl().toString();
if (request.getBody() != null) {
final String unformattedBody = request.getSecuredBody();
final boolean isJsonRequest = request.getHeaders()
.getHeaders(ApiHttpHeaders.CONTENT_TYPE)
.stream()
.findFirst()
.map(ct -> ct.getValue().toLowerCase().contains("json"))
.orElse(true);
if (isJsonRequest) {
String prettyPrint;
try {
prettyPrint = JsonUtils.prettyPrint(unformattedBody);
}
catch (final JsonException e) {
classLogger.warn("pretty print failed", e);
prettyPrint = unformattedBody;
}
output = "Retry #" + attempt + ": " + request + "\n" + httpMethodAndUrl + "\nformatted: " + prettyPrint;
}
else {
output = "Retry #" + attempt + ": " + request + "\n" + request.getMethod().name() + " "
+ request.getUrl() + " " + unformattedBody;
}
}
else {
output = "Retry #" + attempt + ": " + request + "\n" + httpMethodAndUrl + " ";
}
if (response != null) {
output += "\nFailure response: " + response.getStatusCode() + "\n" + response + "\n"
+ Optional.ofNullable(response.getBody())
.map(body -> JsonUtils.prettyPrint(response.getBodyAsString().orElse("")))
.orElse("");
}
return output;
}
/**
* @deprecated max parallel requests are limited by underlying HTTP client
* @param maxRetries number of retries before giving up
* @param maxParallelRequests maximum number of parallel retry requests
*/
@Deprecated
public RetryMiddleware(final int maxParallelRequests, final int maxRetries) {
this(maxRetries, RetryRequestMiddleware.DEFAULT_INITIAL_DELAY, RetryRequestMiddleware.DEFAULT_MAX_DELAY,
RetryRequestMiddleware.DEFAULT_RETRY_STATUS_CODES, null);
}
/**
* @deprecated max parallel requests are limited by underlying HTTP client
* @param maxRetries number of retries before giving up
* @param maxParallelRequests maximum number of parallel retry requests
* @param statusCodes response status codes to be retried
*/
@Deprecated
public RetryMiddleware(final int maxParallelRequests, final int maxRetries, final List statusCodes) {
this(maxRetries, RetryRequestMiddleware.DEFAULT_INITIAL_DELAY, RetryRequestMiddleware.DEFAULT_MAX_DELAY,
statusCodes, null);
}
/**
* @deprecated max parallel requests are limited by underlying HTTP client
* @param maxRetries number of retries before giving up
* @param maxParallelRequests maximum number of parallel retry requests
* @param delay initial delay before retry
* @param maxDelay maximum delay before retry
*/
@Deprecated
public RetryMiddleware(final int maxParallelRequests, final int maxRetries, final long delay, final long maxDelay) {
this(maxRetries, delay, maxDelay, RetryRequestMiddleware.DEFAULT_RETRY_STATUS_CODES, null);
}
/**
* @deprecated max parallel requests are limited by underlying HTTP client
* @param maxRetries number of retries before giving up
* @param maxParallelRequests maximum number of parallel retry requests
* @param delay initial delay before retry
* @param maxDelay maximum delay before retry
* @param statusCodes response status codes to be retried
*/
@Deprecated
public RetryMiddleware(final int maxParallelRequests, final int maxRetries, final long delay, final long maxDelay,
List statusCodes) {
this(maxRetries, delay, maxDelay, statusCodes, null);
}
@Override
public CompletableFuture> invoke(final ApiHttpRequest request,
final Function>> next) {
return failsafeExecutor.getStageAsync(() -> next.apply(request));
}
@Override
public void close() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy