/// <summary> /// Gets the retry decision based on the request error /// </summary> internal static RetryDecisionWithReason GetRetryDecisionWithReason( IRequestError error, IExtendedRetryPolicy policy, IStatement statement, Configuration config, int retryCount) { var ex = error.Exception; if (ex is SocketException || ex is OverloadedException || ex is IsBootstrappingException || ex is TruncateException || ex is OperationTimedOutException) { if (ex is SocketException exception) { RequestExecution.Logger.Verbose("Socket error " + exception.SocketErrorCode); } // For PREPARE requests, retry on next host var decision = statement == null && ex is OperationTimedOutException ? RetryDecision.Retry(null, false) : policy.OnRequestError(statement, config, ex, retryCount); return(new RetryDecisionWithReason(decision, RequestExecution.GetErrorType(error))); } if (ex is ReadTimeoutException e) { return(new RetryDecisionWithReason( policy.OnReadTimeout( statement, e.ConsistencyLevel, e.RequiredAcknowledgements, e.ReceivedAcknowledgements, e.WasDataRetrieved, retryCount), RequestErrorType.ReadTimeOut )); } if (ex is WriteTimeoutException e1) { return(new RetryDecisionWithReason( policy.OnWriteTimeout( statement, e1.ConsistencyLevel, e1.WriteType, e1.RequiredAcknowledgements, e1.ReceivedAcknowledgements, retryCount), RequestErrorType.WriteTimeOut )); } if (ex is UnavailableException e2) { return(new RetryDecisionWithReason( policy.OnUnavailable(statement, e2.Consistency, e2.RequiredReplicas, e2.AliveReplicas, retryCount), RequestErrorType.Unavailable )); } // Any other Exception just throw it return(new RetryDecisionWithReason(RetryDecision.Rethrow(), RequestExecution.GetErrorType(error))); }
/// <summary> /// Handles the response of a (re)prepare request and retries to execute on the same connection /// </summary> private void ReprepareResponseHandler(IRequestError error, Response response, Host host) { try { if (error?.Exception != null) { HandleRequestError(error, host); return; } RequestExecution.ValidateResult(response); var output = ((ResultResponse)response).Output; if (!(output is OutputPrepared outputPrepared)) { _parent.SetCompleted( new DriverInternalError("Expected prepared response, obtained " + output.GetType().FullName)); return; } if (_parent.Statement is BoundStatement boundStatement) { // Use the latest result metadata id boundStatement.PreparedStatement.ResultMetadataId = outputPrepared.ResultMetadataId; } Send(_request, host, HandleResponse); } catch (Exception exception) { //There was an issue while sending _parent.SetCompleted(exception); } }
/// <summary> /// Checks if the exception is either a Cassandra response error or a socket exception to retry or failover if necessary. /// </summary> private void HandleRequestError(IRequestError error, Host host) { var ex = error.Exception; RequestExecution.Logger.Info("RequestHandler received exception {0}", ex.ToString()); if (ex is PreparedQueryNotFoundException foundException && (_parent.Statement is BoundStatement || _parent.Statement is BatchStatement)) { PrepareAndRetry(foundException.UnknownId, host); return; } if (ex is NoHostAvailableException exception) { //A NoHostAvailableException when trying to retrieve _parent.SetNoMoreHosts(exception, this); return; } _triedHosts[host.Address] = ex; if (ex is OperationTimedOutException) { RequestExecution.Logger.Warning(ex.Message); var connection = _connection; if (connection == null) { RequestExecution.Logger.Error("Connection must not be null"); } else { // Checks how many timed out operations are in the connection _session.CheckHealth(host, connection); } } var retryInformation = GetRetryDecisionWithReason( error, _parent.RetryPolicy, _parent.Statement, _session.Cluster.Configuration, _retryCount); switch (retryInformation.Decision.DecisionType) { case RetryDecision.RetryDecisionType.Rethrow: _parent.SetCompleted(ex); break; case RetryDecision.RetryDecisionType.Ignore: // The error was ignored by the RetryPolicy, return an empty rowset _parent.SetCompleted(null, FillRowSet(RowSet.Empty(), null)); break; case RetryDecision.RetryDecisionType.Retry: //Retry the Request using the new consistency level Retry(retryInformation.Decision.RetryConsistencyLevel, retryInformation.Decision.UseCurrentHost, host); break; } _requestObserver.OnRequestError(host, retryInformation.Reason, retryInformation.Decision.DecisionType); }
private void EventHandler(IRequestError error, Response response, long timestamp) { if (!(response is EventResponse)) { Connection.Logger.Error("Unexpected response type for event: " + response.GetType().Name); return; } CassandraEventResponse?.Invoke(this, ((EventResponse)response).CassandraEventArgs); }
/// <summary> /// Asynchronously marks the provided operations as completed and invoke the callbacks with the exception. /// </summary> internal static void CallbackMultiple(IEnumerable <OperationState> ops, IRequestError error, long timestamp) { Task.Factory.StartNew(() => { foreach (var state in ops) { var callback = state.SetCompleted(); callback(error, null, timestamp); } }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); }
/// <summary> /// Attempts to transition the underlying Task to RanToCompletion or Faulted state. /// </summary> public static void TrySetRequestError <T>(this TaskCompletionSource <T> tcs, IRequestError error, T result) { if (error?.Exception != null) { tcs.TrySetException(error.Exception); } else { tcs.TrySetResult(result); } }
/// <summary> /// Marks this operation as completed and invokes the callback with the exception using the default task scheduler. /// Its safe to call this method multiple times as the underlying callback will be invoked just once. /// </summary> public void InvokeCallback(IRequestError error, long timestamp) { var callback = SetCompleted(); if (callback == Noop) { return; } //Invoke the callback in a new thread in the thread pool //This way we don't let the user block on a thread used by the Connection Task.Factory.StartNew(() => callback(error, null, timestamp), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); }
private static RequestErrorType GetErrorType(IRequestError error) { if (error.Exception is OperationTimedOutException) { return(RequestErrorType.ClientTimeout); } if (error.Unsent) { return(RequestErrorType.Unsent); } return(error.IsServerError ? RequestErrorType.Other : RequestErrorType.Aborted); }
private void HandleResponse(IRequestError error, Response response, Host host) { if (_parent.HasCompleted()) { //Do nothing else, another execution finished already set the response return; } try { if (error?.Exception != null) { HandleRequestError(error, host); return; } HandleRowSetResult(response); } catch (Exception handlerException) { _parent.SetCompleted(handlerException); } }
public void OnOperationReceive(IRequestError error, Response response, long timestamp) { if (!_enabledNodeTimerMetrics) { return; } try { var startTimestamp = Volatile.Read(ref _startTimestamp); if (startTimestamp == 0) { MetricsOperationObserver.Logger.Warning("Start timestamp wasn't recorded, discarding this measurement."); return; } _operationTimer.Record((timestamp - startTimestamp) * MetricsOperationObserver.Factor); } catch (Exception ex) { MetricsOperationObserver.LogError(ex); } }
/// <summary> /// Returns an action that capture the parameters closure /// </summary> private Action <MemoryStream, long> CreateResponseAction( ResultMetadata resultMetadata, ISerializer serializer, FrameHeader header, Action <IRequestError, Response, long> callback) { var compressor = Compressor; void DeserializeResponseStream(MemoryStream stream, long timestamp) { Response response = null; IRequestError error = null; var nextPosition = stream.Position + header.BodyLength; try { Stream plainTextStream = stream; if (header.Flags.HasFlag(HeaderFlags.Compression)) { plainTextStream = compressor.Decompress(new WrappedStream(stream, header.BodyLength)); plainTextStream.Position = 0; } response = FrameParser.Parse(new Frame(header, plainTextStream, serializer, resultMetadata)); } catch (Exception caughtException) { error = RequestError.CreateClientError(caughtException, false); } if (response is ErrorResponse errorResponse) { error = RequestError.CreateServerError(errorResponse); response = null; } //We must advance the position of the stream manually in case it was not correctly parsed stream.Position = nextPosition; callback(error, response, timestamp); } return(DeserializeResponseStream); }
public void OnOperationReceive(IRequestError error, Response response, long timestamp) { }