All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.glue.ExponentialHttpRequestRetryStrategy Maven / Gradle / Ivy

The newest version!
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package software.amazon.glue;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.UnknownHostException;
import java.time.Instant;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import javax.net.ssl.SSLException;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.apache.hc.client5.http.utils.DateUtils;
import org.apache.hc.core5.concurrent.CancellableDependency;
import org.apache.hc.core5.http.ConnectionClosedException;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.Method;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue;
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableSet;

/**
 * Defines an exponential HTTP request retry strategy and provides the same characteristics as the
 * {@link org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy}, using the following list
 * of non-retriable I/O exception classes:
 *
 * 
    *
  • InterruptedIOException *
  • UnknownHostException *
  • ConnectException *
  • ConnectionClosedException *
  • NoRouteToHostException *
  • SSLException *
* * The following retriable HTTP status codes are defined: * *
    *
  • SC_TOO_MANY_REQUESTS (429) *
  • SC_BAD_GATEWAY (502) *
  • SC_SERVICE_UNAVAILABLE (503) *
  • SC_GATEWAY_TIMEOUT (504) *
* * Most code and behavior is taken from {@link * org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy}, with minor modifications to * {@link #getRetryInterval(HttpResponse, int, HttpContext)} to achieve exponential backoff. */ class ExponentialHttpRequestRetryStrategy implements HttpRequestRetryStrategy { private final int maxRetries; private final Set> nonRetriableExceptions; private final Set retriableCodes; ExponentialHttpRequestRetryStrategy(int maximumRetries) { Preconditions.checkArgument( maximumRetries > 0, "Cannot set retries to %s, the value must be positive", maximumRetries); this.maxRetries = maximumRetries; this.retriableCodes = ImmutableSet.of( HttpStatus.SC_TOO_MANY_REQUESTS, HttpStatus.SC_SERVICE_UNAVAILABLE, HttpStatus.SC_BAD_GATEWAY, HttpStatus.SC_GATEWAY_TIMEOUT); this.nonRetriableExceptions = ImmutableSet.of( InterruptedIOException.class, UnknownHostException.class, ConnectException.class, ConnectionClosedException.class, NoRouteToHostException.class, SSLException.class); } @Override public boolean retryRequest( HttpRequest request, IOException exception, int execCount, HttpContext context) { if (execCount > maxRetries) { // Do not retry if over max retries return false; } if (nonRetriableExceptions.contains(exception.getClass())) { return false; } else { for (Class rejectException : nonRetriableExceptions) { if (rejectException.isInstance(exception)) { return false; } } } if (request instanceof CancellableDependency && ((CancellableDependency) request).isCancelled()) { return false; } // Retry if the request is considered idempotent return Method.isIdempotent(request.getMethod()); } @Override public boolean retryRequest(HttpResponse response, int execCount, HttpContext context) { return execCount <= maxRetries && retriableCodes.contains(response.getCode()); } @Override public TimeValue getRetryInterval(HttpResponse response, int execCount, HttpContext context) { // a server may send a 429 / 503 with a Retry-After header // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After Header header = response.getFirstHeader(HttpHeaders.RETRY_AFTER); TimeValue retryAfter = null; if (header != null) { String value = header.getValue(); try { retryAfter = TimeValue.ofSeconds(Long.parseLong(value)); } catch (NumberFormatException ignore) { Instant retryAfterDate = DateUtils.parseStandardDate(value); if (retryAfterDate != null) { retryAfter = TimeValue.ofMilliseconds(retryAfterDate.toEpochMilli() - System.currentTimeMillis()); } } if (TimeValue.isPositive(retryAfter)) { return retryAfter; } } int delayMillis = 1000 * (int) Math.min(Math.pow(2.0, (long) execCount - 1), 64.0); int jitter = ThreadLocalRandom.current().nextInt(Math.max(1, (int) (delayMillis * 0.1))); return TimeValue.ofMilliseconds(delayMillis + jitter); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy