public void Test_MixedJson_ToString()
        {
            var ctx = new QueryErrorContext
            {
                ClientContextId = "contextId",
                HttpStatus      = System.Net.HttpStatusCode.InternalServerError,
                Errors          = new System.Collections.Generic.List <Couchbase.Query.Error>
                {
                    new Couchbase.Query.Error()
                    {
                        Code           = 8675309,
                        Message        = "example error",
                        AdditionalData = new Dictionary <string, object>()
                        {
                            { "foobar", Newtonsoft.Json.Linq.JObject.Parse("{ \"example\": 1 }") }
                        }
                    }
                }
            };

            var json = ctx.ToString();

            Assert.Contains("foobar", json);

            var roundTrip = JsonSerializer.Deserialize <KeyValueErrorContext>(json, Couchbase.Core.InternalSerializationContext.Default.KeyValueErrorContext);

            Assert.Equal(ctx.ClientContextId, roundTrip.ClientContextId);
        }
        public static Exception ThrowExceptionOnError <T>(this IQueryResult <T> result, QueryErrorContext context)
        {
            foreach (var error in result.Errors)
            {
                if (error.Code == 3000)
                {
                    throw new ParsingFailureException(context);
                }

                if (PreparedErrorCodes.Contains(error.Code))
                {
                    throw new PreparedStatementException(context);
                }

                if (error.Code == 4300 && error.Message.Contains("index") &&
                    error.Message.Contains("already exists"))
                {
                    throw new IndexExistsException(context);
                }

                if (error.Code >= 4000 && error.Code < 5000)
                {
                    throw new PlanningFailureException(context);
                }

                if (error.Code == 12004 || error.Code == 12016 ||
                    error.Code == 5000 && error.Message.Contains("index") && error.Message.Contains("not found"))
                {
                    throw new IndexNotFoundException(context);
                }

                if (error.Code == 5000 && error.Message.Contains("index") && error.Message.Contains("already exists"))
                {
                    throw new IndexExistsException(context);
                }

                if (error.Code >= 5000 && error.Code < 6000)
                {
                    throw new InternalServerFailureException();
                }

                if (error.Code == 12009 && error.Message.Contains("CAS mismatch"))
                {
                    throw new CasMismatchException(context);
                }

                if (error.Code == 12009)
                {
                    throw new DmlFailureException(context);
                }

                if (error.Code >= 10000 && error.Code < 11000 || error.Code == 13014)
                {
                    throw new AuthenticationFailureException(context);
                }

                if (error.Code >= 12000 && error.Code < 13000 || error.Code >= 14000 && error.Code < 15000)
                {
                    throw new IndexFailureException(context);
                }
            }

            throw new CouchbaseException(context);
        }
Ejemplo n.º 3
0
 public PlanningFailureException(QueryErrorContext context) : base(context.Message)
 {
     Context = context;
 }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
0
 public PreparedStatementException(QueryErrorContext context)
 {
     Context = context;
 }
 public PlanningFailureException(QueryErrorContext context)
 {
     Context = context;
 }
 public PreparedStatementException(QueryErrorContext context) : base(context.Message ?? "Prepared statement error")
 {
     Context = context;
 }
Ejemplo n.º 8
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);
        }
Ejemplo n.º 9
0
 public IndexFailureException(QueryErrorContext context)
 {
     Context = context;
 }
Ejemplo n.º 10
0
 public IndexFailureException(QueryErrorContext context) : base(context.Message)
 {
     Context = context;
 }
Ejemplo n.º 11
0
 public DmlFailureException(QueryErrorContext context) : base("The server failed to execute a DML query")
 {
     Context = context;
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Create the appropriate Exception for an error context
        /// </summary>
        /// <typeparam name="T">Result type</typeparam>
        /// <param name="result">Result</param>
        /// <param name="context">Error context</param>
        /// <returns>Exception</returns>
        public static CouchbaseException CreateExceptionForError <T>(this IQueryResult <T> result, QueryErrorContext context)
        {
            foreach (var error in result.Errors)
            {
                if (error.Code == 3000)
                {
                    return(new ParsingFailureException(context));
                }

                if (PreparedErrorCodes.Contains(error.Code))
                {
                    return(new PreparedStatementException(context));
                }

                if (error.Code == 4300 && error.Message.Contains("index", StringComparison.OrdinalIgnoreCase) &&
                    error.Message.Contains("already exists", StringComparison.OrdinalIgnoreCase))
                {
                    return(new IndexExistsException(context));
                }

                if (error.Code >= 4000 && error.Code < 5000)
                {
                    return(new PlanningFailureException(context));
                }

                if (error.Code == 12004 || error.Code == 12016 ||
                    error.Code == 5000 && error.Message.Contains("index", StringComparison.OrdinalIgnoreCase) &&
                    error.Message.Contains("not found", StringComparison.OrdinalIgnoreCase))
                {
                    return(new IndexNotFoundException(context));
                }

                if (error.Code == 5000 && error.Message.Contains("index", StringComparison.OrdinalIgnoreCase) &&
                    error.Message.Contains("already exists", StringComparison.OrdinalIgnoreCase))
                {
                    return(new IndexExistsException(context));
                }

                if (error.Code >= 5000 && error.Code < 6000)
                {
                    return(new InternalServerFailureException());
                }

                if (error.Code == 12009)
                {
                    if (error.Message.Contains("CAS mismatch", StringComparison.OrdinalIgnoreCase) || error.Reason.Code == 12033)
                    {
                        return(new CasMismatchException(context));
                    }
                    if (error.Reason.Code == 17014)
                    {
                        return(new DocumentNotFoundException(context));
                    }
                    if (error.Reason.Code == 17012)
                    {
                        return(new DocumentExistsException(context));
                    }

                    return(new DmlFailureException(context));
                }

                if (error.Code >= 10000 && error.Code < 11000 || error.Code == 13014)
                {
                    return(new AuthenticationFailureException(context));
                }

                if (error.Code >= 12000 && error.Code < 13000 || error.Code >= 14000 && error.Code < 15000)
                {
                    return(new IndexFailureException(context));
                }

                //Rate Limiting Errors
                if (error.Code == 1191)
                {
                    return(new RateLimitedException(RateLimitedReason.RequestRateLimitReached, context));
                }
                if (error.Code == 1192)
                {
                    return(new RateLimitedException(RateLimitedReason.ConcurrentRequestLimitReached, context));
                }
                if (error.Code == 1193)
                {
                    return(new RateLimitedException(RateLimitedReason.NetworkIngressRateLimitReached, context));
                }
                if (error.Code == 1194)
                {
                    return(new RateLimitedException(RateLimitedReason.NetworkEgressRateLimitReached, context));
                }
            }

            return(new CouchbaseException(context));
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Create/throw the appropriate Exception given an error context
 /// </summary>
 /// <typeparam name="T">Result type</typeparam>
 /// <param name="result">Result</param>
 /// <param name="context">Error context</param>
 /// <returns></returns>
 public static Exception ThrowExceptionOnError <T>(this IQueryResult <T> result, QueryErrorContext context)
 {
     throw CreateExceptionForError(result, context);
 }
Ejemplo n.º 14
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);
        }