Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CosmosClientOptions and CosmosClientBuilder: Adds client level support for EnableContentResponseOnWrite #2145

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ namespace Microsoft.Azure.Cosmos
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Handlers;
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
using Microsoft.Azure.Cosmos.Serialization.HybridRow.IO;
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Layouts;
Expand All @@ -32,7 +34,8 @@ public ItemBatchOperation(
string id = null,
Stream resourceStream = null,
TransactionalBatchItemRequestOptions requestOptions = null,
CosmosDiagnosticsContext diagnosticsContext = null)
CosmosDiagnosticsContext diagnosticsContext = null,
CosmosClientContext cosmosClientContext = null)
j82w marked this conversation as resolved.
Show resolved Hide resolved
{
this.OperationType = operationType;
this.OperationIndex = operationIndex;
Expand All @@ -41,6 +44,7 @@ public ItemBatchOperation(
this.ResourceStream = resourceStream;
this.RequestOptions = requestOptions;
this.DiagnosticsContext = diagnosticsContext;
this.ClientContext = cosmosClientContext;
}

public ItemBatchOperation(
Expand All @@ -58,6 +62,7 @@ public ItemBatchOperation(
this.ResourceStream = resourceStream;
this.RequestOptions = requestOptions;
this.DiagnosticsContext = null;
this.ClientContext = containerCore.ClientContext;
}

public PartitionKey? PartitionKey { get; internal set; }
Expand All @@ -80,6 +85,8 @@ public ItemBatchOperation(

internal Documents.PartitionKey ParsedPartitionKey { get; set; }

private readonly CosmosClientContext ClientContext;

internal Memory<byte> ResourceBody
{
get
Expand Down Expand Up @@ -167,18 +174,6 @@ internal static Result WriteOperation(ref RowWriter writer, TypeArgument typeArg
}
}

if (ItemRequestOptions.ShouldSetNoContentHeader(
options.EnableContentResponseOnWrite,
options.EnableContentResponseOnRead,
operation.OperationType))
{
r = writer.WriteBool("minimalReturnPreference", true);
if (r != Result.Success)
{
return r;
}
}

if (options.IfMatchEtag != null)
{
r = writer.WriteString("ifMatch", options.IfMatchEtag);
Expand Down Expand Up @@ -250,6 +245,18 @@ internal static Result WriteOperation(ref RowWriter writer, TypeArgument typeArg
}
}

if (RequestInvokerHandler.ShouldSetNoContentResponseHeaders(operation.RequestOptions,
operation.ClientContext?.ClientOptions,
operation.OperationType,
ResourceType.Document))
{
r = writer.WriteBool("minimalReturnPreference", true);
if (r != Result.Success)
{
return r;
}
}

return Result.Success;
}

Expand Down Expand Up @@ -369,8 +376,9 @@ public ItemBatchOperation(
PartitionKey partitionKey,
T resource,
string id = null,
TransactionalBatchItemRequestOptions requestOptions = null)
: base(operationType, operationIndex, partitionKey: partitionKey, id: id, requestOptions: requestOptions)
TransactionalBatchItemRequestOptions requestOptions = null,
CosmosClientContext cosmosClientContext = null)
: base(operationType, operationIndex, partitionKey: partitionKey, id: id, requestOptions: requestOptions, cosmosClientContext: cosmosClientContext)
{
this.Resource = resource;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ public class TransactionalBatchItemRequestOptions : RequestOptions
/// </remarks>
public bool? EnableContentResponseOnWrite { get; set; }

/// <summary>
/// Gets or sets the boolean to only return the headers and status code in
/// the Cosmos DB response for read item operations like ReadItem
/// This removes the resource from the response. This reduces networking and CPU load by not sending
/// the resource back over the network and serializing it on the client.
/// </summary>
/// <remarks>
/// This is optimal for workloads where the returned resource is not used.
/// </remarks>
internal bool? EnableContentResponseOnRead { get; set; }

internal static TransactionalBatchItemRequestOptions FromItemRequestOptions(ItemRequestOptions itemRequestOptions)
{
if (itemRequestOptions == null)
Expand All @@ -55,7 +44,6 @@ internal static TransactionalBatchItemRequestOptions FromItemRequestOptions(Item
IfNoneMatchEtag = itemRequestOptions.IfNoneMatchEtag,
Properties = itemRequestOptions.Properties,
EnableContentResponseOnWrite = itemRequestOptions.EnableContentResponseOnWrite,
EnableContentResponseOnRead = itemRequestOptions.EnableContentResponseOnRead,
IsEffectivePartitionKeyRouting = itemRequestOptions.IsEffectivePartitionKeyRouting
};
return batchItemRequestOptions;
Expand Down
20 changes: 20 additions & 0 deletions Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,26 @@ public ConnectionMode ConnectionMode
/// <seealso cref="CosmosClientBuilder.WithThrottlingRetryOptions(TimeSpan, int)"/>
public TimeSpan? MaxRetryWaitTimeOnRateLimitedRequests { get; set; }

/// <summary>
/// Gets or sets the boolean to only return the headers and status code in
/// the Cosmos DB response for write item operation like Create, Upsert, Patch and Replace.
/// Setting the option to false will cause the response to have a null resource. This reduces networking and CPU load by not sending
/// the resource back over the network and serializing it on the client.
asketagarwal marked this conversation as resolved.
Show resolved Hide resolved
asketagarwal marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <remarks>
/// <para>This is optimal for workloads where the returned resource is not used.</para>
/// <para>This option can be overriden by similar property in ItemRequestOptions and TransactionalBatchItemRequestOptions</para>
/// </remarks>
asketagarwal marked this conversation as resolved.
Show resolved Hide resolved
/// <seealso cref="CosmosClientBuilder.WithContentResponseOnWriteEnabled(bool)"/>
/// <seealso cref="ItemRequestOptions.EnableContentResponseOnWrite"/>
/// <seealso cref="TransactionalBatchItemRequestOptions.EnableContentResponseOnWrite"/>
#if PREVIEW
asketagarwal marked this conversation as resolved.
Show resolved Hide resolved
public
#else
internal
#endif
bool? EnableContentResponseOnWrite { get; set; }

/// <summary>
/// (Direct/TCP) Controls the amount of idle time after which unused connections are closed.
/// </summary>
Expand Down
26 changes: 26 additions & 0 deletions Microsoft.Azure.Cosmos/src/Fluent/CosmosClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,32 @@ public CosmosClientBuilder WithHttpClientFactory(Func<HttpClient> httpClientFact
return this;
}

/// <summary>
/// Gets or sets the boolean to only return the headers and status code in
/// the Cosmos DB response for write item operation like Create, Upsert, Patch and Replace.
/// Setting the option to false will cause the response to have a null resource. This reduces networking and CPU load by not sending
/// the resource back over the network and serializing it on the client.
/// </summary>
/// <param name="contentResponseOnWriteEnabled">a boolean indicating whether payload will be included in the response or not.</param>
/// <remarks>
/// <para>
/// This option can be overriden by similar property in ItemRequestOptions and TransactionalBatchItemRequestOptions
/// </para>
/// </remarks>
/// <returns>The <see cref="CosmosClientBuilder"/> object</returns>
/// <seealso cref="ItemRequestOptions.EnableContentResponseOnWrite"/>
/// <seealso cref="TransactionalBatchItemRequestOptions.EnableContentResponseOnWrite"/>
#if PREVIEW
public
#else
internal
#endif
CosmosClientBuilder WithContentResponseOnWriteEnabled(bool contentResponseOnWriteEnabled)
{
this.clientOptions.EnableContentResponseOnWrite = contentResponseOnWriteEnabled;
return this;
}

/// <summary>
/// The event handler to be invoked before the request is sent.
/// </summary>
Expand Down
67 changes: 67 additions & 0 deletions Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ public override async Task<ResponseMessage> SendAsync(
promotedRequestOptions.PopulateRequestOptions(request);
}

// Adds the NoContent header if not already added based on Client Level flag
if (RequestInvokerHandler.ShouldSetNoContentResponseHeaders(request.RequestOptions,
this.client.ClientOptions,
request.OperationType,
request.ResourceType))
{
request.Headers.Add(HttpConstants.HttpHeaders.Prefer, HttpConstants.HttpHeaderValues.PreferReturnMinimal);
}

await this.ValidateAndSetConsistencyLevelAsync(request);
(bool isError, ResponseMessage errorResponse) = await this.EnsureValidClientAsync(request);
if (isError)
Expand Down Expand Up @@ -381,5 +390,63 @@ private async Task ValidateAndSetConsistencyLevelAsync(RequestMessage requestMes
}
}
}

internal static bool ShouldSetNoContentResponseHeaders(RequestOptions requestOptions,
CosmosClientOptions clientOptions,
OperationType operationType,
ResourceType resourceType)
{
if (resourceType != ResourceType.Document)
{
return false;
}

if (requestOptions == null)
{
return RequestInvokerHandler.IsClientNoResponseSet(clientOptions, operationType);
}

if (requestOptions is ItemRequestOptions itemRequestOptions)
{
if (itemRequestOptions.EnableContentResponseOnWrite.HasValue)
{
return RequestInvokerHandler.IsItemNoRepsonseSet(itemRequestOptions.EnableContentResponseOnWrite.Value, operationType);
}
else
{
return RequestInvokerHandler.IsClientNoResponseSet(clientOptions, operationType);
}
}

if (requestOptions is TransactionalBatchItemRequestOptions batchRequestOptions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the new configuration all based on ItemRequestOptions only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ContentResponse flag is also available for TransactionalBatchRequestOptions

{
if (batchRequestOptions.EnableContentResponseOnWrite.HasValue)
{
return RequestInvokerHandler.IsItemNoRepsonseSet(batchRequestOptions.EnableContentResponseOnWrite.Value, operationType);
}
else
{
return RequestInvokerHandler.IsClientNoResponseSet(clientOptions, operationType);
}
}

return false;
}

private static bool IsItemNoRepsonseSet(bool enableContentResponseOnWrite, OperationType operationType)
{
return !enableContentResponseOnWrite &&
(operationType == OperationType.Create ||
operationType == OperationType.Replace ||
operationType == OperationType.Upsert ||
operationType == OperationType.Patch);
}

private static bool IsClientNoResponseSet(CosmosClientOptions clientOptions, OperationType operationType)
{
return clientOptions != null
&& clientOptions.EnableContentResponseOnWrite.HasValue
&& RequestInvokerHandler.IsItemNoRepsonseSet(clientOptions.EnableContentResponseOnWrite.Value, operationType);
}
}
}
50 changes: 0 additions & 50 deletions Microsoft.Azure.Cosmos/src/RequestOptions/ItemRequestOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,27 +118,6 @@ public ConsistencyLevel? ConsistencyLevel
/// </remarks>
public bool? EnableContentResponseOnWrite { get; set; }

/// <summary>
/// Gets or sets the boolean to only return the headers and status code in
/// the Cosmos DB response for read item operations like ReadItemAsync
/// This removes the resource from the response. This reduces networking and CPU load by not sending
/// the resource back over the network and serializing it on the client.
/// </summary>
/// <example>
/// <code language="c#">
/// <![CDATA[
/// ItemRequestOption requestOptions = new ItemRequestOptions() { EnableContentResponseOnRead = true };
/// ItemResponse itemResponse = await this.container.ReadItemAsync<ToDoActivity>(tests, new PartitionKey(test.status), requestOptions);
/// Assert.AreEqual(HttpStatusCode.Created, itemResponse.StatusCode);
/// Assert.IsNull(itemResponse.Resource);
/// ]]>
/// </code>
/// </example>
/// <remarks>
/// This is optimal for workloads where the returned resource is not used.
/// </remarks>
internal bool? EnableContentResponseOnRead { get; set; }

/// <summary>
/// Fill the CosmosRequestMessage headers with the set properties
/// </summary>
Expand All @@ -163,36 +142,7 @@ internal override void PopulateRequestOptions(RequestMessage request)
}

RequestOptions.SetSessionToken(request, this.SessionToken);

if (ItemRequestOptions.ShouldSetNoContentHeader(
this.EnableContentResponseOnWrite,
this.EnableContentResponseOnRead,
request.OperationType))
{
request.Headers.Add(HttpConstants.HttpHeaders.Prefer, HttpConstants.HttpHeaderValues.PreferReturnMinimal);
}

base.PopulateRequestOptions(request);
}

internal static bool ShouldSetNoContentHeader(
bool? enableContentResponseOnWrite,
bool? enableContentResponseOnRead,
OperationType operationType)
{
if (enableContentResponseOnRead.HasValue &&
!enableContentResponseOnRead.Value &&
operationType == OperationType.Read)
{
return true;
}

return enableContentResponseOnWrite.HasValue &&
!enableContentResponseOnWrite.Value &&
(operationType == OperationType.Create ||
operationType == OperationType.Replace ||
operationType == OperationType.Upsert ||
operationType == OperationType.Patch);
}
}
}
3 changes: 2 additions & 1 deletion Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,8 @@ private async Task<ResponseMessage> ProcessResourceOperationAsBulkStreamAsync(
id: itemId,
resourceStream: streamPayload,
requestOptions: batchItemRequestOptions,
diagnosticsContext: diagnosticsContext);
diagnosticsContext: diagnosticsContext,
cosmosClientContext: this);

TransactionalBatchOperationResult batchOperationResult = await cosmosContainerCore.BatchExecutor.AddAsync(
itemBatchOperation,
Expand Down
Loading