예제 #1
0
        private async Task <IQueryResult <T> > ExecuteQuery <T>(QueryOptions options, ITypeSerializer serializer, IInternalSpan span)
        {
            // try get Query node
            var queryUri = _serviceUriProvider.GetRandomQueryUri();

            span.WithRemoteAddress(queryUri);
            using var encodingSpan = span.StartPayloadEncoding();
            var body = options.GetFormValuesAsJson();

            encodingSpan.Dispose();

            _logger.LogDebug("Sending query {contextId} to node {endpoint}.", options.CurrentContextId, queryUri);

            QueryResultBase <T> queryResult;

            using var content = new StringContent(body, System.Text.Encoding.UTF8, MediaType.Json);
            try
            {
                using var dispatchSpan = span.StartDispatch();
                var response = await HttpClient.PostAsync(queryUri, content, options.Token).ConfigureAwait(false);

                dispatchSpan.Dispose();

                var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                if (serializer is IStreamingTypeDeserializer streamingDeserializer)
                {
                    queryResult = new StreamingQueryResult <T>(stream, streamingDeserializer);
                }
                else
                {
                    queryResult = new BlockQueryResult <T>(stream, serializer);
                }

                queryResult.HttpStatusCode = response.StatusCode;
                queryResult.Success        = response.StatusCode == HttpStatusCode.OK;

                //read the header and stop when we reach the queried rows
                await queryResult.InitializeAsync(options.Token).ConfigureAwait(false);

                if (response.StatusCode != HttpStatusCode.OK || queryResult.MetaData?.Status != QueryStatus.Success)
                {
                    var currentContextId = options.CurrentContextId ?? Guid.Empty.ToString();

                    _logger.LogDebug("Request {currentContextId} has failed because {status}.",
                                     currentContextId, queryResult.MetaData?.Status);

                    if (queryResult.ShouldRetry(EnhancedPreparedStatementsEnabled))
                    {
                        if (queryResult.Errors.Any(x => x.Code == 4040 && EnhancedPreparedStatementsEnabled))
                        {
                            //clear the cache of stale query plan
                            var statement = options.StatementValue ?? string.Empty;
                            if (_queryCache.TryRemove(statement, out var queryPlan))
                            {
                                _logger.LogDebug("Query plan is stale for {currentContextId}. Purging plan {queryPlanName}.", currentContextId, queryPlan.Name);
                            }
                            ;
                        }
                        _logger.LogDebug("Request {currentContextId} is being retried.", currentContextId);
                        return(queryResult);
                    }

                    var context = new QueryErrorContext
                    {
                        ClientContextId = options.CurrentContextId,
                        Parameters      = options.GetAllParametersAsJson(),
                        Statement       = options.ToString(),
                        Message         = GetErrorMessage(queryResult, currentContextId, response.StatusCode),
                        Errors          = queryResult.Errors,
                        HttpStatus      = response.StatusCode,
                        QueryStatus     = queryResult.MetaData?.Status ?? QueryStatus.Fatal
                    };

                    if (queryResult.MetaData?.Status == QueryStatus.Timeout)
                    {
                        if (options.IsReadOnly)
                        {
                            throw new AmbiguousTimeoutException
                                  {
                                      Context = context
                                  };
                        }

                        throw new UnambiguousTimeoutException
                              {
                                  Context = context
                              };
                    }
                    queryResult.ThrowExceptionOnError(context);
                }
            }
            catch (OperationCanceledException e)
            {
                var context = new QueryErrorContext
                {
                    ClientContextId = options.CurrentContextId,
                    Parameters      = options.GetAllParametersAsJson(),
                    Statement       = options.ToString(),
                    HttpStatus      = HttpStatusCode.RequestTimeout,
                    QueryStatus     = QueryStatus.Fatal
                };

                _logger.LogDebug(LoggingEvents.QueryEvent, e, "Request timeout.");
                if (options.IsReadOnly)
                {
                    throw new UnambiguousTimeoutException("The query was timed out via the Token.", e)
                          {
                              Context = context
                          };
                }
                throw new AmbiguousTimeoutException("The query was timed out via the Token.", e)
                      {
                          Context = context
                      };
            }
            catch (HttpRequestException e)
            {
                _logger.LogDebug(LoggingEvents.QueryEvent, e, "Request canceled");

                var context = new QueryErrorContext
                {
                    ClientContextId = options.CurrentContextId,
                    Parameters      = options.GetAllParametersAsJson(),
                    Statement       = options.ToString(),
                    HttpStatus      = HttpStatusCode.RequestTimeout,
                    QueryStatus     = QueryStatus.Fatal
                };

                throw new RequestCanceledException("The query was canceled.", e)
                      {
                          Context = context
                      };
            }

            _logger.LogDebug($"Request {options.CurrentContextId} has succeeded.");
            return(queryResult);
        }
예제 #2
0
        private async Task <IQueryResult <T> > ExecuteQuery <T>(QueryOptions options, IDataMapper dataMapper)
        {
            // try get Query node
            var queryUri = _serviceUriProvider.GetRandomQueryUri();
            var body     = options.GetFormValuesAsJson();

            QueryResultBase <T> queryResult;

            using (var content = new StringContent(body, System.Text.Encoding.UTF8, MediaType.Json))
            {
                try
                {
                    var response = await HttpClient.PostAsync(queryUri, content, options.Token).ConfigureAwait(false);

                    var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                    if (_serializer is IStreamingTypeDeserializer streamingDeserializer)
                    {
                        queryResult = new StreamingQueryResult <T>(stream, streamingDeserializer);
                    }
                    else
                    {
                        queryResult = new BlockQueryResult <T>(stream, _serializer);
                    }

                    queryResult.HttpStatusCode = response.StatusCode;
                    queryResult.Success        = response.StatusCode == HttpStatusCode.OK;

                    //read the header and stop when we reach the queried rows
                    await queryResult.InitializeAsync(options.Token).ConfigureAwait(false);

                    if (response.StatusCode != HttpStatusCode.OK || queryResult.MetaData.Status != QueryStatus.Success)
                    {
                        Log.LogDebug($"Request {options.CurrentContextId} has failed because {queryResult.MetaData.Status}.");
                        if (queryResult.ShouldRetry())
                        {
                            return(queryResult);
                        }
                        var context = new QueryErrorContext
                        {
                            Message     = queryResult.Message,
                            Errors      = queryResult.Errors,
                            HttpStatus  = response.StatusCode,
                            QueryStatus = queryResult.MetaData.Status
                        };

                        if (queryResult.MetaData.Status == QueryStatus.Timeout)
                        {
                            if (options.IsReadOnly)
                            {
                                throw new AmbiguousTimeoutException
                                      {
                                          Context = context
                                      };
                            }

                            throw new UnambiguousTimeoutException
                                  {
                                      Context = context
                                  };
                        }
                        queryResult.ThrowExceptionOnError(context);
                    }
                }
                catch (OperationCanceledException e)
                {
                    Log.LogDebug(LoggingEvents.QueryEvent, e, "Request timeout.");
                    if (options.IsReadOnly)
                    {
                        throw new UnambiguousTimeoutException("The query was timed out via the Token.", e);
                    }
                    throw new AmbiguousTimeoutException("The query was timed out via the Token.", e);
                }
                catch (HttpRequestException e)
                {
                    Log.LogDebug(LoggingEvents.QueryEvent, e, "Request canceled");
                    throw new RequestCanceledException("The query was canceled.", e);
                }
            }
            Log.LogDebug($"Request {options.CurrentContextId} has succeeded.");
            return(queryResult);
        }
예제 #3
0
        private async Task <IQueryResult <T> > ExecuteQuery <T>(QueryOptions options, ITypeSerializer serializer, IRequestSpan span)
        {
            var currentContextId = options.CurrentContextId ?? DefaultClientContextId;

            QueryErrorContext ErrorContextFactory(QueryResultBase <T> failedQueryResult, HttpStatusCode statusCode)
            {
                // We use a local function to capture context like options and currentContextId

                return(new()
                {
                    ClientContextId = options.CurrentContextId,
                    Parameters = options.GetAllParametersAsJson(),
                    Statement = options.ToString(),
                    Message = GetErrorMessage(failedQueryResult, currentContextId, statusCode),
                    Errors = failedQueryResult.Errors,
                    HttpStatus = statusCode,
                    QueryStatus = failedQueryResult.MetaData?.Status ?? QueryStatus.Fatal
                });
            }

            // try get Query node
            Uri queryUri = options.LastDispatchedNode ?? _serviceUriProvider.GetRandomQueryUri();

            span.WithRemoteAddress(queryUri);
            using var encodingSpan = span.EncodingSpan();
            using var content      = options.GetRequestBody(serializer);
            encodingSpan.Dispose();

            _logger.LogDebug("Sending query {contextId} to node {endpoint}.", options.CurrentContextId, queryUri);

            QueryResultBase <T> queryResult;

            try
            {
                using var dispatchSpan = span.DispatchSpan(options);
                using var httpClient   = CreateHttpClient(options.TimeoutValue);

                var response = await httpClient.PostAsync(queryUri, content, options.Token).ConfigureAwait(false);

                dispatchSpan.Dispose();

                var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                if (serializer is IStreamingTypeDeserializer streamingDeserializer)
                {
                    queryResult = new StreamingQueryResult <T>(stream, streamingDeserializer, ErrorContextFactory);
                }
                else
                {
                    queryResult = new BlockQueryResult <T>(stream, serializer);
                }

                queryResult.HttpStatusCode = response.StatusCode;
                queryResult.Success        = response.StatusCode == HttpStatusCode.OK;

                //read the header and stop when we reach the queried rows
                await queryResult.InitializeAsync(options.Token).ConfigureAwait(false);

                if (response.StatusCode != HttpStatusCode.OK || queryResult.MetaData?.Status != QueryStatus.Success)
                {
                    _logger.LogDebug("Request {currentContextId} has failed because {status}.",
                                     currentContextId, queryResult.MetaData?.Status);

                    if (queryResult.ShouldRetry(EnhancedPreparedStatementsEnabled))
                    {
                        queryResult.NoRetryException = queryResult.CreateExceptionForError(ErrorContextFactory(queryResult, response.StatusCode));
                        if (queryResult.Errors.Any(x => x.Code == 4040 && EnhancedPreparedStatementsEnabled))
                        {
                            //clear the cache of stale query plan
                            var statement = options.StatementValue ?? string.Empty;
                            if (_queryCache.TryRemove(statement, out var queryPlan))
                            {
                                _logger.LogDebug("Query plan is stale for {currentContextId}. Purging plan {queryPlanName}.", currentContextId, queryPlan.Name);
                            }
                        }
                        _logger.LogDebug("Request {currentContextId} is being retried.", currentContextId);
                        return(queryResult);
                    }

                    var context = ErrorContextFactory(queryResult, response.StatusCode);

                    if (queryResult.MetaData?.Status == QueryStatus.Timeout)
                    {
                        if (options.IsReadOnly)
                        {
                            throw new AmbiguousTimeoutException
                                  {
                                      Context = context
                                  };
                        }

                        throw new UnambiguousTimeoutException
                              {
                                  Context = context
                              };
                    }
                    queryResult.ThrowExceptionOnError(context);
                }
                else if (options.StatementValue == TransactionsBeginWork)
                {
                    // Internal support for Transactions query node affinity
                    // If the result has a "txid" row, grab the value and add it to the affinity map.
                    queryResult.MetaData.LastDispatchedToNode = queryUri;
                }
            }
            catch (OperationCanceledException e)
            {
                //treat as an orphaned response
                span.LogOrphaned();

                var context = new QueryErrorContext
                {
                    ClientContextId = options.CurrentContextId,
                    Parameters      = options.GetAllParametersAsJson(),
                    Statement       = options.ToString(),
                    HttpStatus      = HttpStatusCode.RequestTimeout,
                    QueryStatus     = QueryStatus.Fatal
                };

                _logger.LogDebug(LoggingEvents.QueryEvent, e, "Request timeout.");
                if (options.IsReadOnly)
                {
                    throw new UnambiguousTimeoutException("The query was timed out via the Token.", e)
                          {
                              Context = context
                          };
                }
                throw new AmbiguousTimeoutException("The query was timed out via the Token.", e)
                      {
                          Context = context
                      };
            }
            catch (HttpRequestException e)
            {
                _logger.LogDebug(LoggingEvents.QueryEvent, e, "Request canceled");

                //treat as an orphaned response
                span.LogOrphaned();

                var context = new QueryErrorContext
                {
                    ClientContextId = options.CurrentContextId,
                    Parameters      = options.GetAllParametersAsJson(),
                    Statement       = options.ToString(),
                    HttpStatus      = HttpStatusCode.RequestTimeout,
                    QueryStatus     = QueryStatus.Fatal
                };

                throw new RequestCanceledException("The query was canceled.", e)
                      {
                          Context = context
                      };
            }

            _logger.LogDebug($"Request {options.CurrentContextId} has succeeded.");
            return(queryResult);
        }