com.datastax.oss.driver.api.core.retry.RetryPolicy Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.datastax.oss.driver.api.core.retry;
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.connection.ClosedConnectionException;
import com.datastax.oss.driver.api.core.connection.HeartbeatException;
import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy;
import com.datastax.oss.driver.api.core.servererrors.BootstrappingException;
import com.datastax.oss.driver.api.core.servererrors.CoordinatorException;
import com.datastax.oss.driver.api.core.servererrors.FunctionFailureException;
import com.datastax.oss.driver.api.core.servererrors.OverloadedException;
import com.datastax.oss.driver.api.core.servererrors.ProtocolError;
import com.datastax.oss.driver.api.core.servererrors.QueryValidationException;
import com.datastax.oss.driver.api.core.servererrors.ReadFailureException;
import com.datastax.oss.driver.api.core.servererrors.ReadTimeoutException;
import com.datastax.oss.driver.api.core.servererrors.ServerError;
import com.datastax.oss.driver.api.core.servererrors.TruncateException;
import com.datastax.oss.driver.api.core.servererrors.WriteFailureException;
import com.datastax.oss.driver.api.core.servererrors.WriteType;
import com.datastax.oss.driver.api.core.session.Request;
import edu.umd.cs.findbugs.annotations.NonNull;
/**
* Defines the behavior to adopt when a request fails.
*
* For each request, the driver gets a "query plan" (a list of coordinators to try) from the
* {@link LoadBalancingPolicy}, and tries each node in sequence. This policy is invoked if the
* request to that node fails.
*
*
The methods of this interface are invoked on I/O threads, therefore implementations should
* never block. In particular, don't call {@link Thread#sleep(long)} to retry after a delay:
* this would prevent asynchronous processing of other requests, and very negatively impact
* throughput. If the application needs to back off and retry later, this should be implemented in
* client code, not in this policy.
*/
public interface RetryPolicy extends AutoCloseable {
/**
* Whether to retry when the server replied with a {@code READ_TIMEOUT} error; this indicates a
* server-side timeout during a read query, i.e. some replicas did not reply to the
* coordinator in time.
*
* @param request the request that timed out.
* @param cl the requested consistency level.
* @param blockFor the minimum number of replica acknowledgements/responses that were required to
* fulfill the operation.
* @param received the number of replica that had acknowledged/responded to the operation before
* it failed.
* @param dataPresent whether the actual data was amongst the received replica responses. See
* {@link ReadTimeoutException#wasDataPresent()}.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
* @deprecated As of version 4.10, use {@link #onReadTimeoutVerdict(Request, ConsistencyLevel,
* int, int, boolean, int)} instead.
*/
@Deprecated
RetryDecision onReadTimeout(
@NonNull Request request,
@NonNull ConsistencyLevel cl,
int blockFor,
int received,
boolean dataPresent,
int retryCount);
/**
* Whether to retry when the server replied with a {@code READ_TIMEOUT} error; this indicates a
* server-side timeout during a read query, i.e. some replicas did not reply to the
* coordinator in time.
*
* @param request the request that timed out.
* @param cl the requested consistency level.
* @param blockFor the minimum number of replica acknowledgements/responses that were required to
* fulfill the operation.
* @param received the number of replica that had acknowledged/responded to the operation before
* it failed.
* @param dataPresent whether the actual data was amongst the received replica responses. See
* {@link ReadTimeoutException#wasDataPresent()}.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
*/
default RetryVerdict onReadTimeoutVerdict(
@NonNull Request request,
@NonNull ConsistencyLevel cl,
int blockFor,
int received,
boolean dataPresent,
int retryCount) {
RetryDecision decision =
onReadTimeout(request, cl, blockFor, received, dataPresent, retryCount);
return () -> decision;
}
/**
* Whether to retry when the server replied with a {@code WRITE_TIMEOUT} error; this indicates a
* server-side timeout during a write query, i.e. some replicas did not reply to the
* coordinator in time.
*
*
Note that this method will only be invoked for {@link Request#isIdempotent()} idempotent}
* requests: when a write times out, it is impossible to determine with 100% certainty whether the
* mutation was applied or not, so the write is never safe to retry; the driver will rethrow the
* error directly, without invoking the retry policy.
*
* @param request the request that timed out.
* @param cl the requested consistency level.
* @param writeType the type of the write for which the timeout was raised.
* @param blockFor the minimum number of replica acknowledgements/responses that were required to
* fulfill the operation.
* @param received the number of replica that had acknowledged/responded to the operation before
* it failed.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
* @deprecated As of version 4.10, use {@link #onWriteTimeoutVerdict(Request, ConsistencyLevel,
* WriteType, int, int, int)} instead.
*/
@Deprecated
RetryDecision onWriteTimeout(
@NonNull Request request,
@NonNull ConsistencyLevel cl,
@NonNull WriteType writeType,
int blockFor,
int received,
int retryCount);
/**
* Whether to retry when the server replied with a {@code WRITE_TIMEOUT} error; this indicates a
* server-side timeout during a write query, i.e. some replicas did not reply to the
* coordinator in time.
*
*
Note that this method will only be invoked for {@link Request#isIdempotent()} idempotent}
* requests: when a write times out, it is impossible to determine with 100% certainty whether the
* mutation was applied or not, so the write is never safe to retry; the driver will rethrow the
* error directly, without invoking the retry policy.
*
* @param request the request that timed out.
* @param cl the requested consistency level.
* @param writeType the type of the write for which the timeout was raised.
* @param blockFor the minimum number of replica acknowledgements/responses that were required to
* fulfill the operation.
* @param received the number of replica that had acknowledged/responded to the operation before
* it failed.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
*/
default RetryVerdict onWriteTimeoutVerdict(
@NonNull Request request,
@NonNull ConsistencyLevel cl,
@NonNull WriteType writeType,
int blockFor,
int received,
int retryCount) {
RetryDecision decision = onWriteTimeout(request, cl, writeType, blockFor, received, retryCount);
return () -> decision;
}
/**
* Whether to retry when the server replied with an {@code UNAVAILABLE} error; this indicates that
* the coordinator determined that there were not enough replicas alive to perform a query with
* the requested consistency level.
*
* @param request the request that timed out.
* @param cl the requested consistency level.
* @param required the number of replica acknowledgements/responses required to perform the
* operation (with its required consistency level).
* @param alive the number of replicas that were known to be alive by the coordinator node when it
* tried to execute the operation.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
* @deprecated As of version 4.10, use {@link #onUnavailableVerdict(Request, ConsistencyLevel,
* int, int, int)} instead.
*/
@Deprecated
RetryDecision onUnavailable(
@NonNull Request request,
@NonNull ConsistencyLevel cl,
int required,
int alive,
int retryCount);
/**
* Whether to retry when the server replied with an {@code UNAVAILABLE} error; this indicates that
* the coordinator determined that there were not enough replicas alive to perform a query with
* the requested consistency level.
*
* @param request the request that timed out.
* @param cl the requested consistency level.
* @param required the number of replica acknowledgements/responses required to perform the
* operation (with its required consistency level).
* @param alive the number of replicas that were known to be alive by the coordinator node when it
* tried to execute the operation.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
*/
default RetryVerdict onUnavailableVerdict(
@NonNull Request request,
@NonNull ConsistencyLevel cl,
int required,
int alive,
int retryCount) {
RetryDecision decision = onUnavailable(request, cl, required, alive, retryCount);
return () -> decision;
}
/**
* Whether to retry when a request was aborted before we could get a response from the server.
*
*
This can happen in two cases: if the connection was closed due to an external event (this
* will manifest as a {@link ClosedConnectionException}, or {@link HeartbeatException} for a
* heartbeat failure); or if there was an unexpected error while decoding the response (this can
* only be a driver bug).
*
*
Note that this method will only be invoked for {@linkplain Request#isIdempotent()
* idempotent} requests: when execution was aborted before getting a response, it is impossible to
* determine with 100% certainty whether a mutation was applied or not, so a write is never safe
* to retry; the driver will rethrow the error directly, without invoking the retry policy.
*
* @param request the request that was aborted.
* @param error the error.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
* @deprecated As of version 4.10, use {@link #onRequestAbortedVerdict(Request, Throwable, int)}
* instead.
*/
@Deprecated
RetryDecision onRequestAborted(
@NonNull Request request, @NonNull Throwable error, int retryCount);
/**
* Whether to retry when a request was aborted before we could get a response from the server.
*
*
This can happen in two cases: if the connection was closed due to an external event (this
* will manifest as a {@link ClosedConnectionException}, or {@link HeartbeatException} for a
* heartbeat failure); or if there was an unexpected error while decoding the response (this can
* only be a driver bug).
*
*
Note that this method will only be invoked for {@linkplain Request#isIdempotent()
* idempotent} requests: when execution was aborted before getting a response, it is impossible to
* determine with 100% certainty whether a mutation was applied or not, so a write is never safe
* to retry; the driver will rethrow the error directly, without invoking the retry policy.
*
* @param request the request that was aborted.
* @param error the error.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
*/
default RetryVerdict onRequestAbortedVerdict(
@NonNull Request request, @NonNull Throwable error, int retryCount) {
RetryDecision decision = onRequestAborted(request, error, retryCount);
return () -> decision;
}
/**
* Whether to retry when the server replied with a recoverable error (other than {@code
* READ_TIMEOUT}, {@code WRITE_TIMEOUT} or {@code UNAVAILABLE}).
*
*
This can happen for the following errors: {@link OverloadedException}, {@link ServerError},
* {@link TruncateException}, {@link ReadFailureException}, {@link WriteFailureException}.
*
*
The following errors are handled internally by the driver, and therefore will never
* be encountered in this method:
*
*
* - {@link BootstrappingException}: always retried on the next node;
*
- {@link QueryValidationException} (and its subclasses), {@link FunctionFailureException}
* and {@link ProtocolError}: always rethrown.
*
*
* Note that this method will only be invoked for {@link Request#isIdempotent()} idempotent}
* requests: when execution was aborted before getting a response, it is impossible to determine
* with 100% certainty whether a mutation was applied or not, so a write is never safe to retry;
* the driver will rethrow the error directly, without invoking the retry policy.
*
* @param request the request that failed.
* @param error the error.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
* @deprecated As of version 4.10, use {@link #onErrorResponseVerdict(Request,
* CoordinatorException, int)} instead.
*/
@Deprecated
RetryDecision onErrorResponse(
@NonNull Request request, @NonNull CoordinatorException error, int retryCount);
/**
* Whether to retry when the server replied with a recoverable error (other than {@code
* READ_TIMEOUT}, {@code WRITE_TIMEOUT} or {@code UNAVAILABLE}).
*
*
This can happen for the following errors: {@link OverloadedException}, {@link ServerError},
* {@link TruncateException}, {@link ReadFailureException}, {@link WriteFailureException}.
*
*
The following errors are handled internally by the driver, and therefore will never
* be encountered in this method:
*
*
* - {@link BootstrappingException}: always retried on the next node;
*
- {@link QueryValidationException} (and its subclasses), {@link FunctionFailureException}
* and {@link ProtocolError}: always rethrown.
*
*
* Note that this method will only be invoked for {@link Request#isIdempotent()} idempotent}
* requests: when execution was aborted before getting a response, it is impossible to determine
* with 100% certainty whether a mutation was applied or not, so a write is never safe to retry;
* the driver will rethrow the error directly, without invoking the retry policy.
*
* @param request the request that failed.
* @param error the error.
* @param retryCount how many times the retry policy has been invoked already for this request
* (not counting the current invocation).
*/
default RetryVerdict onErrorResponseVerdict(
@NonNull Request request, @NonNull CoordinatorException error, int retryCount) {
RetryDecision decision = onErrorResponse(request, error, retryCount);
return () -> decision;
}
/** Called when the cluster that this policy is associated with closes. */
@Override
void close();
}