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

com.microsoft.azure.documentdb.internal.RetryUtility Maven / Gradle / Ivy

package com.microsoft.azure.documentdb.internal;

import java.io.IOException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.microsoft.azure.documentdb.BridgeInternal;
import com.microsoft.azure.documentdb.Document;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.documentdb.DocumentClientException;
import com.microsoft.azure.documentdb.ResourceResponse;
import com.microsoft.azure.documentdb.RetryOptions;
import com.microsoft.azure.documentdb.internal.directconnectivity.GoneAndRetryWithRetryPolicy;
import com.microsoft.azure.documentdb.internal.routing.ClientCollectionCache;

/**
 * Used internally. A utility class to manage retries for various retryable service errors in the Azure Cosmos DB database service. It
 * invokes a delegate function to execute the target operation. Upon error, it waits a period of time as defined by the
 * RetryPolicy instance before re-issuing the same request. Different RetryPolicy implementations decides the wait
 * period based on its own logic.
 */
public class RetryUtility {

    private final static Logger logger = LoggerFactory.getLogger(RetryUtility.class);
    
    /**
     * Executes the code block in the delegate and retry if needed.
     * 

* This method is used to retry an existing DocumentServiceRequest. * * @param delegate the delegate to execute. * @param documentClient the DocumentClient instance. * @param globalEndpointManager the EndpointManager instance. * @param request the request parameter for the execution. * @return the DocumentServiceResponse instance * @throws DocumentClientException the original exception if retry is not applicable. */ public static DocumentServiceResponse executeDocumentClientRequest( RetryRequestDelegate delegate, DocumentClient documentClient, EndpointManager globalEndpointManager, DocumentServiceRequest request, ClientCollectionCache clientCollectionCache) throws DocumentClientException { DocumentServiceResponse response = null; EndpointDiscoveryRetryPolicy discoveryRetryPolicy = new EndpointDiscoveryRetryPolicy( documentClient.getConnectionPolicy(), globalEndpointManager, request); ResourceThrottleRetryPolicy throttleRetryPolicy = new ResourceThrottleRetryPolicy( documentClient.getConnectionPolicy().getRetryOptions().getMaxRetryAttemptsOnThrottledRequests(), documentClient.getConnectionPolicy().getRetryOptions().getMaxRetryWaitTimeInSeconds()); SessionReadRetryPolicy sessionReadRetryPolicy = new SessionReadRetryPolicy( globalEndpointManager, request, documentClient.getConnectionPolicy().getEnableEndpointDiscovery()); RenameCollectionAwareClientRetryPolicy renameCollectionAwareClientRetryPolicy = new RenameCollectionAwareClientRetryPolicy( clientCollectionCache, documentClient.getConnectionPolicy().getConnectionMode(), globalEndpointManager, request); while (true) { try { logger.trace("Executing DocumentClientRequest {} {} {}", request.getOperationType(), request.getResourceType(), request.getActivityId()); response = delegate.apply(request); break; } catch (DocumentClientException e) { RetryPolicy retryPolicy = null; if (e.getStatusCode() == HttpConstants.StatusCodes.FORBIDDEN && ((e.getSubStatusCode() != null && (e.getSubStatusCode() == HttpConstants.SubStatusCodes.FORBIDDEN_WRITEFORBIDDEN || e.getSubStatusCode() == HttpConstants.SubStatusCodes.DATABASE_ACCOUNT_NOTFOUND)) || e.getCause() instanceof IOException) || (documentClient.getConnectionPolicy().getHandleServiceUnavailableFromProxy() && e.getStatusCode() == HttpConstants.StatusCodes.SERVICE_UNAVAILABLE && e.getResponseHeaders() != null && e.getResponseHeaders().get(HttpConstants.HttpHeaders.SERVER_VERSION) == null)) { // If HttpStatusCode is 403 (Forbidden) and // SubStatusCode is (WriteForbidden) or 1008 (DatabaseAccountNotFound) // Or the exception is IOException // Or HttpStatusCode is 503 (Service unavailable) and // Service Version header is missing (i.e, thrown from proxy and did not reach backend) and // user has opted in for refresh // invoke the endpoint discovery retry policy retryPolicy = discoveryRetryPolicy; } else if (e.getStatusCode() == HttpConstants.StatusCodes.TOO_MANY_REQUESTS) { // If HttpStatusCode is 429 (Too Many Requests), invoke the // throttle retry policy retryPolicy = throttleRetryPolicy; } else if (e.getStatusCode() == HttpConstants.StatusCodes.NOTFOUND && e.getSubStatusCode() != null && e.getSubStatusCode() == HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE) { // If HttpStatusCode is 404 (NotFound) and SubStatusCode is // 1002 (ReadSessionNotAvailable), invoke the session read retry policy retryPolicy = sessionReadRetryPolicy; } boolean retry = (retryPolicy != null && retryPolicy.shouldRetry(e)); if (!retry && retryPolicy instanceof SessionReadRetryPolicy) { retry = renameCollectionAwareClientRetryPolicy.shouldRetry(e); } if (!retry) { logger.trace("Execution encountered exception: {}, status code {} sub status code {}. Won't retry!", e.getMessage(), e.getStatusCode(), e.getSubStatusCode()); throw e; } logger.info("Execution encountered exception: {}, status code {} sub status code {}. Will retry in {}ms", e.getMessage(), e.getStatusCode(), e.getSubStatusCode(), retryPolicy.getRetryAfterInMilliseconds()); RetryUtility.delayForRetry(retryPolicy); BridgeInternal.updateAuthTokenHeader(documentClient, request); } } logger.trace("Executing DocumentClientRequest finished. {}", request.getActivityId()); return response; } /** * Executes the code block in the delegate and retry if needed. *

* This method is used to retry an existing DocumentServiceRequest. * * @param delegate the delegate to execute. * @param request the request parameter for the execution. * @throws DocumentClientException the original exception if retry is not applicable. * @return the DocumentServiceResponse instance */ public static DocumentServiceResponse executeStoreClientRequest(RetryRequestDelegate delegate, RetryOptions retryOptions, DocumentServiceRequest request, RefreshAuthTokenDelegate refreshAuthTokenDelegate) throws DocumentClientException { DocumentServiceResponse response = null; GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, retryOptions.getRetryWithInitialBackoffTime(), retryOptions.getRetryWithBackoffMultiplier()); while (true) { try { logger.trace("Executing DocumentClientRequest {} {} {}", request.getOperationType(), request.getResourceType(), request.getActivityId()); response = delegate.apply(request); break; } catch (DocumentClientException e) { RetryPolicy retryPolicy = null; if (e.getStatusCode() == HttpConstants.StatusCodes.RETRY_WITH || e.getStatusCode() == HttpStatus.SC_GONE) { // if HttpStatusCode is 449 ( retryWith ) or 410 ( gone exception ). invoke the GoneAndRetry policy retryPolicy = goneAndRetryWithRetryPolicy; } boolean retry = (retryPolicy != null && retryPolicy.shouldRetry(e)); if (!retry) { logger.trace("Execution encountered exception: {}, status code {} sub status code {}. Won't retry!", e.getMessage(), e.getStatusCode(), e.getSubStatusCode()); throw e; } logger.info("Execution encountered exception: {}, status code {} sub status code {}. Will retry in {}ms", e.getMessage(), e.getStatusCode(), e.getSubStatusCode(), retryPolicy.getRetryAfterInMilliseconds()); RetryUtility.delayForRetry(retryPolicy); refreshAuthTokenDelegate.apply(request); } } logger.trace("Executing DocumentClientRequest finished. {}", request.getActivityId()); return response; } /** * Executes the code block in the delegate and retry if needed. *

* This method is used to retry a document create operation for partitioned collection * in the case where the request failed because the collection has changed. * * @param delegate the delegate to execute. * @param clientCollectionCache the cache the maps collection ResourceId or resource name to collection * @param resourcePath the path to the collection resource. * @throws DocumentClientException the original exception if retry is not applicable. * @return the response resource. */ public static ResourceResponse executeCreateDocument( RetryCreateDocumentDelegate delegate, ClientCollectionCache clientCollectionCache, String resourcePath) throws DocumentClientException { ResourceResponse result = null; PartitionKeyMismatchRetryPolicy keyMismatchRetryPolicy = new PartitionKeyMismatchRetryPolicy( resourcePath, clientCollectionCache); while (true) { try { logger.trace("Executing createDocument {}", resourcePath); result = delegate.apply(); break; } catch (DocumentClientException e) { RetryPolicy retryPolicy = null; if (e.getStatusCode() == HttpConstants.StatusCodes.BADREQUEST && e.getSubStatusCode() != null && e.getSubStatusCode() == HttpConstants.SubStatusCodes.PARTITION_KEY_MISMATCH) { // If HttpStatusCode is 404 (NotFound) and SubStatusCode is // 1001 (PartitionKeyMismatch), invoke the partition key mismatch retry policy retryPolicy = keyMismatchRetryPolicy; } boolean retry = (retryPolicy != null && retryPolicy.shouldRetry(e)); if (!retry) { logger.trace("Execution encountered exception: {}, status code {} sub status code {}. Won't retry!", e.getMessage(), e.getStatusCode(), e.getSubStatusCode()); throw e; } logger.info("Execution encountered exception: {}, status code {} sub status code {}. Will retry in {}ms", e.getMessage(), e.getStatusCode(), e.getSubStatusCode(), retryPolicy.getRetryAfterInMilliseconds()); RetryUtility.delayForRetry(retryPolicy); } } logger.trace("Executing DocumentClientRequest finished. {}", resourcePath); return result; } private static void delayForRetry(RetryPolicy retryPolicy) { final long delay = retryPolicy.getRetryAfterInMilliseconds(); if (delay > 0) { try { Thread.sleep(delay); } catch (InterruptedException e) { // Ignore the interruption. } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy