Ejemplo n.º 1
0
        /// <summary>
        /// Executes a <see cref="ISearchQuery" /> request including any <see cref="ISearchOptions" /> parameters asynchronously.
        /// </summary>
        /// <returns>A <see cref="ISearchResult"/> wrapped in a <see cref="Task"/> for awaiting on.</returns>
        public async Task <ISearchResult> QueryAsync(SearchRequest searchRequest, CancellationToken cancellationToken = default)
        {
            // try get Search node
            var searchUri  = _serviceUriProvider.GetRandomSearchUri();
            var uriBuilder = new UriBuilder(searchUri)
            {
                Path = $"api/index/{searchRequest.Index}/query"
            };

            var searchResult = new SearchResult();
            var searchBody   = searchRequest.ToJson();

            try
            {
                using var content = new StringContent(searchBody, Encoding.UTF8, MediaType.Json);
                var response = await HttpClient.PostAsync(uriBuilder.Uri, content, cancellationToken).ConfigureAwait(false);

                using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        searchResult = await _dataMapper.MapAsync <SearchResult>(stream, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        using var reader = new StreamReader(stream);
                        var errorResult = await reader.ReadToEndAsync().ConfigureAwait(false);
                    }
                }

                searchResult.HttpStatusCode = response.StatusCode;
                if (searchResult.ShouldRetry())
                {
                    UpdateLastActivity();
                    return(searchResult);
                }
            }
            catch (OperationCanceledException e)
            {
                Log.LogDebug(LoggingEvents.SearchEvent, e, "Search request timeout.");
                throw new AmbiguousTimeoutException("The query was timed out via the Token.", e);
            }
            catch (HttpRequestException e)
            {
                Log.LogDebug(LoggingEvents.SearchEvent, e, "Search request cancelled.");
                throw new RequestCanceledException("The query was canceled.", e);
            }
            UpdateLastActivity();
            return(searchResult);
        }
Ejemplo n.º 2
0
        private Uri GetIndexUri(string?indexName = null)
        {
            var searchUri = _serviceUriProvider.GetRandomSearchUri();
            var builder   = new UriBuilder(searchUri)
            {
                Path = "api/index"
            };

            if (!string.IsNullOrWhiteSpace(indexName))
            {
                builder.Path += $"/{indexName}";
            }

            return(builder.Uri);
        }
Ejemplo n.º 3
0
        public async Task <ISearchResult> QueryAsync(SearchRequest searchRequest, CancellationToken cancellationToken = default)
        {
            using var rootSpan = RootSpan(OuterRequestSpans.ServiceSpan.SearchQuery)
                                 .WithLocalAddress();

            using var encodingSpan = rootSpan.EncodingSpan();

            // try get Search nodes
            var searchUri = _serviceUriProvider.GetRandomSearchUri();

            rootSpan.WithRemoteAddress(searchUri);

            var uriBuilder = new UriBuilder(searchUri)
            {
                Path = $"api/index/{searchRequest.Index}/query"
            };

            _logger.LogDebug("Sending FTS query with a context id {contextId} to server {searchUri}",
                             searchRequest.ClientContextId, searchUri);

            var searchResult = new SearchResult();
            var searchBody   = searchRequest.ToJson();

            string?errors = null;

            try
            {
                using var content = new StringContent(searchBody, Encoding.UTF8, MediaType.Json);
                encodingSpan.Dispose();
                using var dispatchSpan = rootSpan.DispatchSpan(searchRequest);
                using var httpClient   = CreateHttpClient();
                var response = await httpClient.PostAsync(uriBuilder.Uri, content, cancellationToken).ConfigureAwait(false);

                dispatchSpan.Dispose();

                using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        searchResult = await _dataMapper.MapAsync <SearchResult>(stream, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        using var reader = new StreamReader(stream);
                        errors           = await reader.ReadToEndAsync().ConfigureAwait(false);

                        var json       = JsonConvert.DeserializeObject <JObject>(errors);
                        var queryError = json?.SelectToken("error");

                        //If the query service returned a top level error then
                        //use it otherwise the error is in the response body
                        if (queryError != null)
                        {
                            errors = queryError.Value <string>() ?? "";
                        }

                        var ctx = new SearchErrorContext
                        {
                            HttpStatus      = response.StatusCode,
                            IndexName       = searchRequest.Index,
                            ClientContextId = searchRequest.ClientContextId,
                            Statement       = searchRequest.Statement,
                            Errors          = errors,
                            Query           = searchRequest.ToJson(),
                            Message         = errors
                        };

                        //Rate limiting errors
                        if (response.StatusCode == (HttpStatusCode)429)
                        {
                            if (errors.Contains("num_concurrent_requests"))
                            {
                                throw new RateLimitedException(RateLimitedReason.ConcurrentRequestLimitReached,
                                                               ctx);
                            }
                            if (errors.Contains("num_queries_per_min"))
                            {
                                throw new RateLimitedException(RateLimitedReason.ConcurrentRequestLimitReached,
                                                               ctx);
                            }
                            if (errors.Contains("ingress_mib_per_min"))
                            {
                                throw new RateLimitedException(RateLimitedReason.NetworkIngressRateLimitReached,
                                                               ctx);
                            }
                            if (errors.Contains("egress_mib_per_min"))
                            {
                                throw new RateLimitedException(RateLimitedReason.NetworkEgressRateLimitReached,
                                                               ctx);
                            }
                        }
                        //Quota limiting errors
                        if (response.StatusCode == HttpStatusCode.BadRequest)
                        {
                            if (errors.Contains("index not found"))
                            {
                                throw new IndexNotFoundException("The search index was not found on the server.")
                                      {
                                          Context = ctx
                                      };
                            }
                            if (errors.Contains("num_fts_indexes"))
                            {
                                throw new QuotaLimitedException(QuotaLimitedReason.MaximumNumberOfIndexesReached,
                                                                ctx);
                            }
                        }

                        //Internal service errors
                        if (response.StatusCode == HttpStatusCode.InternalServerError)
                        {
                            throw new InternalServerFailureException {
                                      Context = ctx
                            };
                        }

                        //Authentication errors
                        if (response.StatusCode == HttpStatusCode.Forbidden ||
                            response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            throw new AuthenticationFailureException(ctx);
                        }

                        throw new CouchbaseException(errors)
                              {
                                  Context = ctx
                              };
                    }
                }

                searchResult.HttpStatusCode = response.StatusCode;
                if (searchResult.ShouldRetry())
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        searchResult.NoRetryException = new CouchbaseException()
                        {
                            Context = new SearchErrorContext
                            {
                                HttpStatus      = response.StatusCode,
                                IndexName       = searchRequest.Index,
                                ClientContextId = searchRequest.ClientContextId,
                                Statement       = searchRequest.Statement,
                                Errors          = errors,
                                Query           = searchRequest.ToJson()
                            }
                        };
                    }
                    UpdateLastActivity();
                    return(searchResult);
                }
            }
            catch (OperationCanceledException e)
            {
                //treat as an orphaned response
                rootSpan.LogOrphaned();

                _logger.LogDebug(LoggingEvents.SearchEvent, e, "Search request timeout.");
                throw new AmbiguousTimeoutException("The query was timed out via the Token.", e)
                      {
                          Context = new SearchErrorContext
                          {
                              HttpStatus      = HttpStatusCode.RequestTimeout,
                              IndexName       = searchRequest.Index,
                              ClientContextId = searchRequest.ClientContextId,
                              Statement       = searchRequest.Statement,
                              Errors          = errors,
                              Query           = searchRequest.ToJson()
                          }
                      };
            }
            catch (HttpRequestException e)
            {
                //treat as an orphaned response
                rootSpan.LogOrphaned();

                _logger.LogDebug(LoggingEvents.SearchEvent, e, "Search request cancelled.");
                throw new RequestCanceledException("The query was canceled.", e)
                      {
                          Context = new SearchErrorContext
                          {
                              HttpStatus      = HttpStatusCode.RequestTimeout,
                              IndexName       = searchRequest.Index,
                              ClientContextId = searchRequest.ClientContextId,
                              Statement       = searchRequest.Statement,
                              Errors          = errors,
                              Query           = searchRequest.ToJson()
                          }
                      };
            }
            UpdateLastActivity();
            return(searchResult);
        }
Ejemplo n.º 4
0
        public async Task <ISearchResult> QueryAsync(SearchRequest searchRequest, CancellationToken cancellationToken = default)
        {
            using var rootSpan = RootSpan(OuterRequestSpans.ServiceSpan.SearchQuery)
                                 .WithLocalAddress();

            using var encodingSpan = rootSpan.EncodingSpan();

            // try get Search nodes
            var searchUri = _serviceUriProvider.GetRandomSearchUri();

            rootSpan.WithRemoteAddress(searchUri);

            var uriBuilder = new UriBuilder(searchUri)
            {
                Path = $"api/index/{searchRequest.Index}/query"
            };

            _logger.LogDebug("Sending FTS query with a context id {contextId} to server {searchUri}",
                             searchRequest.ClientContextId, searchUri);

            var searchResult = new SearchResult();
            var searchBody   = searchRequest.ToJson();

            string?errors = null;

            try
            {
                using var content = new StringContent(searchBody, Encoding.UTF8, MediaType.Json);
                encodingSpan.Dispose();
                using var dispatchSpan = rootSpan.DispatchSpan(searchRequest);
                var response = await HttpClient.PostAsync(uriBuilder.Uri, content, cancellationToken).ConfigureAwait(false);

                dispatchSpan.Dispose();
                using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        searchResult = await _dataMapper.MapAsync <SearchResult>(stream, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        using var reader = new StreamReader(stream);
                        errors           = await reader.ReadToEndAsync().ConfigureAwait(false);
                    }
                }

                searchResult.HttpStatusCode = response.StatusCode;
                if (searchResult.ShouldRetry())
                {
                    UpdateLastActivity();
                    return(searchResult);
                }
            }
            catch (OperationCanceledException e)
            {
                _logger.LogDebug(LoggingEvents.SearchEvent, e, "Search request timeout.");
                throw new AmbiguousTimeoutException("The query was timed out via the Token.", e)
                      {
                          Context = new SearchErrorContext
                          {
                              HttpStatus      = HttpStatusCode.RequestTimeout,
                              IndexName       = searchRequest.Index,
                              ClientContextId = searchRequest.ClientContextId,
                              Statement       = searchRequest.Statement,
                              Errors          = errors,
                              Query           = searchRequest.ToJson()
                          }
                      };
            }
            catch (HttpRequestException e)
            {
                _logger.LogDebug(LoggingEvents.SearchEvent, e, "Search request cancelled.");
                throw new RequestCanceledException("The query was canceled.", e)
                      {
                          Context = new SearchErrorContext
                          {
                              HttpStatus      = HttpStatusCode.RequestTimeout,
                              IndexName       = searchRequest.Index,
                              ClientContextId = searchRequest.ClientContextId,
                              Statement       = searchRequest.Statement,
                              Errors          = errors,
                              Query           = searchRequest.ToJson()
                          }
                      };
            }
            UpdateLastActivity();
            return(searchResult);
        }