/// <summary> /// Defines whether to retry and at which consistency level on a write timeout. /// <p> This method triggers a maximum of one retry. If <c>writeType == /// WriteType.BATCH_LOG</c>, the write is retried with the initial consistency /// level. If <c>writeType == WriteType.UNLOGGED_BATCH</c> and at least one /// replica acknowleged, the write is retried with a lower consistency level /// (with unlogged batch, a write timeout can <b>always</b> mean that part of the /// batch haven't been persisted at' all, even if <c>receivedAcks > 0</c>). /// For other <c>writeType</c>, if we know the write has been persisted on /// at least one replica, we ignore the exception. Otherwise, an exception is /// thrown.</p> /// </summary> /// <param name="query"> the original query that timeouted. </param> /// <param name="cl"> the original consistency level of the write that timeouted. /// </param> /// <param name="writeType"> the type of the write that timeouted. </param> /// <param name="requiredAcks"> the number of acknowledgments that were required /// to achieve the requested consistency level. </param> /// <param name="receivedAcks"> the number of acknowledgments that had been /// received by the time the timeout exception was raised. </param> /// <param name="nbRetry"> the number of retry already performed for this /// operation. </param> /// /// <returns>a RetryDecision as defined above.</returns> public RetryDecision OnWriteTimeout(IStatement query, ConsistencyLevel cl, string writeType, int requiredAcks, int receivedAcks, int nbRetry) { if (nbRetry != 0) { return(RetryDecision.Rethrow()); } switch (writeType) { case "SIMPLE": case "BATCH": // Since we provide atomicity there is no point in retrying return(RetryDecision.Ignore()); case "COUNTER": // We should not retry counters, period! return(RetryDecision.Ignore()); case "UNLOGGED_BATCH": // Since only part of the batch could have been persisted, // retry with whatever consistency should allow to persist all return(MaxLikelyToWorkCl(receivedAcks)); case "BATCH_LOG": return(RetryDecision.Retry(cl)); } return(RetryDecision.Rethrow()); }
/// <summary> /// Gets the retry decision based on the exception from Cassandra /// </summary> public RetryDecision GetRetryDecision(Exception ex) { RetryDecision decision = RetryDecision.Rethrow(); if (ex is SocketException) { decision = RetryDecision.Retry(null); } else if (ex is OverloadedException || ex is IsBootstrappingException || ex is TruncateException) { decision = RetryDecision.Retry(null); } else if (ex is ReadTimeoutException) { var e = ex as ReadTimeoutException; decision = _retryPolicy.OnReadTimeout(_statement, e.ConsistencyLevel, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, e.WasDataRetrieved, _retryCount); } else if (ex is WriteTimeoutException) { var e = ex as WriteTimeoutException; decision = _retryPolicy.OnWriteTimeout(_statement, e.ConsistencyLevel, e.WriteType, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, _retryCount); } else if (ex is UnavailableException) { var e = ex as UnavailableException; decision = _retryPolicy.OnUnavailable(_statement, e.Consistency, e.RequiredReplicas, e.AliveReplicas, _retryCount); } return(decision); }
/// <summary> /// The default implementation triggers a retry on the next host in the query plan with the same consistency level, /// regardless of the statement's idempotence, for historical reasons. /// </summary> public RetryDecision OnRequestError(IStatement statement, Configuration config, Exception ex, int nbRetry) { if (ex is OperationTimedOutException && !config.QueryOptions.RetryOnTimeout) { return(RetryDecision.Rethrow()); } return(RetryDecision.Retry(null, false)); }
/// <summary> /// Defines whether to retry and at which consistency level on a write timeout. /// <p> This method triggers a maximum of one retry, and only in the case of a /// <c>WriteType.BATCH_LOG</c> write. The reasoning for the retry in that /// case is that write to the distributed batch log is tried by the coordinator /// of the write against a small subset of all the node alive in the local /// datacenter. Hence, a timeout usually means that none of the nodes in that /// subset were alive but the coordinator hasn't' detected them as dead. By the /// time we get the timeout the dead nodes will likely have been detected as dead /// and the retry has thus a high change of success.</p> /// </summary> /// <param name="query"> the original query that timeouted. </param> /// <param name="cl"> the original consistency level of the write that timeouted. /// </param> /// <param name="writeType"> the type of the write that timeouted. </param> /// <param name="requiredAcks"> the number of acknowledgments that were required /// to achieve the requested consistency level. </param> /// <param name="receivedAcks"> the number of acknowledgments that had been /// received by the time the timeout exception was raised. </param> /// <param name="nbRetry"> the number of retry already performed for this /// operation. </param> /// /// <returns><c>RetryDecision.retry(cl)</c> if no retry attempt has yet /// been tried and <c>writeType == WriteType.BATCH_LOG</c>, /// <c>RetryDecision.rethrow()</c> otherwise.</returns> public RetryDecision OnWriteTimeout(IStatement query, ConsistencyLevel cl, string writeType, int requiredAcks, int receivedAcks, int nbRetry) { if (nbRetry != 0) { return(RetryDecision.Rethrow()); } // If the batch log write failed, retry the operation as this might just be we were unlucky at picking candidtes return(writeType == "BATCH_LOG" ? RetryDecision.Retry(cl) : RetryDecision.Rethrow()); }
/// <inheritdoc /> public RetryDecision OnRequestError(IStatement stmt, Configuration config, Exception ex, int nbRetry) { if (stmt != null && stmt.IsIdempotent == true) { if (_extendedChildPolicy != null) { return(_extendedChildPolicy.OnRequestError(stmt, config, ex, nbRetry)); } return(RetryDecision.Retry(null, false)); } return(RetryDecision.Rethrow()); }
/// <summary> /// Defines whether to retry and at which consistency level on a read timeout. /// <p> This method triggers a maximum of one retry, and only if enough replica /// had responded to the read request but data was not retrieved amongst those. /// Indeed, that case usually means that enough replica are alive to satisfy the /// consistency but the coordinator picked a dead one for data retrieval, not /// having detected that replica as dead yet. The reasoning for retrying then is /// that by the time we get the timeout the dead replica will likely have been /// detected as dead and the retry has a high change of success.</p> /// </summary> /// <param name="query"> the original query that timed out. </param> /// <param name="cl"> the original consistency level of the read that timed out. /// </param> /// <param name="requiredResponses"> the number of responses that were required /// to achieve the requested consistency level. </param> /// <param name="receivedResponses"> the number of responses that had been /// received by the time the timeout exception was raised. </param> /// <param name="dataRetrieved"> whether actual data (by opposition to data /// checksum) was present in the received responses. </param> /// <param name="nbRetry"> the number of retry already performed for this /// operation. </param> /// /// <returns><c>RetryDecision.Retry(cl)</c> if no retry attempt has yet /// been tried and <c>receivedResponses >= requiredResponses && /// !dataRetrieved</c>, <c>RetryDecision.Rethrow()</c> /// otherwise.</returns> public RetryDecision OnReadTimeout(IStatement query, ConsistencyLevel cl, int requiredResponses, int receivedResponses, bool dataRetrieved, int nbRetry) { if (nbRetry != 0) { return(RetryDecision.Rethrow()); } return(receivedResponses >= requiredResponses && !dataRetrieved ? RetryDecision.Retry(cl) : RetryDecision.Rethrow()); }
private static RetryDecision MaxLikelyToWorkCl(int knownOk) { if (knownOk >= 3) { return(RetryDecision.Retry(ConsistencyLevel.Three)); } if (knownOk >= 2) { return(RetryDecision.Retry(ConsistencyLevel.Two)); } if (knownOk >= 1) { return(RetryDecision.Retry(ConsistencyLevel.One)); } return(RetryDecision.Rethrow()); }
/// <summary> /// Defines whether to retry and at which consistency level on a read timeout. /// <p> This method triggers a maximum of one retry. If less replica responsed /// than required by the consistency level (but at least one replica did /// respond), the operation is retried at a lower consistency level. If enough /// replica responded but data was not retrieve, the operation is retried with /// the initial consistency level. Otherwise, an exception is thrown.</p> /// </summary> /// <param name="query"> the original query that timeouted. </param> /// <param name="cl"> the original consistency level of the read that timeouted. /// </param> /// <param name="requiredResponses"> the number of responses that were required /// to achieve the requested consistency level. </param> /// <param name="receivedResponses"> the number of responses that had been /// received by the time the timeout exception was raised. </param> /// <param name="dataRetrieved"> whether actual data (by opposition to data /// checksum) was present in the received responses. </param> /// <param name="nbRetry"> the number of retry already performed for this /// operation. </param> /// /// <returns>a RetryDecision as defined above.</returns> public RetryDecision OnReadTimeout(IStatement query, ConsistencyLevel cl, int requiredResponses, int receivedResponses, bool dataRetrieved, int nbRetry) { if (nbRetry != 0) { return(RetryDecision.Rethrow()); } if (receivedResponses < requiredResponses) { // Tries the biggest CL that is expected to work return(MaxLikelyToWorkCl(receivedResponses)); } return(!dataRetrieved?RetryDecision.Retry(cl) : RetryDecision.Rethrow()); }
static RetryDecision GetRetryDecision(Query query, QueryValidationException exc, IRetryPolicy policy, int queryRetries) { if (exc is OverloadedException) { return(RetryDecision.Retry(null)); } else if (exc is IsBootstrappingException) { return(RetryDecision.Retry(null)); } else if (exc is TruncateException) { return(RetryDecision.Retry(null)); } else if (exc is ReadTimeoutException) { var e = exc as ReadTimeoutException; return(policy.OnReadTimeout(query, e.ConsistencyLevel, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, e.WasDataRetrieved, queryRetries)); } else if (exc is WriteTimeoutException) { var e = exc as WriteTimeoutException; return(policy.OnWriteTimeout(query, e.ConsistencyLevel, e.WriteType, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, queryRetries)); } else if (exc is UnavailableException) { var e = exc as UnavailableException; return(policy.OnUnavailable(query, e.Consistency, e.RequiredReplicas, e.AliveReplicas, queryRetries)); } else if (exc is AlreadyExistsException) { return(RetryDecision.Rethrow()); } else if (exc is InvalidConfigurationInQueryException) { return(RetryDecision.Rethrow()); } else if (exc is PreparedQueryNotFoundException) { return(RetryDecision.Rethrow()); } else if (exc is ProtocolErrorException) { return(RetryDecision.Rethrow()); } else if (exc is InvalidQueryException) { return(RetryDecision.Rethrow()); } else if (exc is UnauthorizedException) { return(RetryDecision.Rethrow()); } else if (exc is SyntaxError) { return(RetryDecision.Rethrow()); } else if (exc is ServerErrorException) { return(null); } else { return(null); } }