/// <inheritdoc /> public Task <HttpResponseMessage> DeleteAsync(string path, IRequestSpan parentSpan, IRequestSpan encodeSpan, CancellationToken token) { var requestUri = GetUri(path); parentSpan.WithRemoteAddress(requestUri); encodeSpan.Dispose(); using var dispatchSpan = parentSpan.DispatchSpan(); return(HttpClient.DeleteAsync(requestUri, token)); }
/// <inheritdoc /> public Task <HttpResponseMessage> PostAsync(string path, IRequestSpan parentSpan, IRequestSpan encodeSpan, CancellationToken token, EventingFunction eventingFunction = null) { var requestUri = GetUri(path); parentSpan.WithRemoteAddress(requestUri); var content = eventingFunction != null ? new StringContent(eventingFunction.ToJson()) : new StringContent(string.Empty); encodeSpan.Dispose(); using var dispatchSpan = parentSpan.DispatchSpan(); return(HttpClient.PostAsync(requestUri, content, token)); }
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 var queryUri = _serviceUriProvider.GetRandomQueryUri(); span.WithRemoteAddress(queryUri); using var encodingSpan = span.EncodingSpan(); 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.DispatchSpan(options); 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)) { 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); } } 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); }