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

[Hotfix-Preview] Query: Adds environment variable for overriding EnableOptimisticDirectExecution default #4312

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ClientOfficialVersion>3.38.0</ClientOfficialVersion>
<ClientOfficialVersion>3.38.1</ClientOfficialVersion>
<ClientPreviewVersion>3.39.0</ClientPreviewVersion>
<ClientPreviewSuffixVersion>preview.0</ClientPreviewSuffixVersion>
<DirectVersion>3.32.0</DirectVersion>
<ClientPreviewSuffixVersion>preview.1</ClientPreviewSuffixVersion>
<DirectVersion>3.32.1</DirectVersion>
<EncryptionOfficialVersion>2.0.4</EncryptionOfficialVersion>
<EncryptionPreviewVersion>2.1.0</EncryptionPreviewVersion>
<EncryptionPreviewSuffixVersion>preview4</EncryptionPreviewSuffixVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class QueryRequestOptions : RequestOptions
/// <value>
/// Direct (optimistic) execution offers improved performance for several kinds of queries such as a single partition streaming query.
/// </value>
public bool EnableOptimisticDirectExecution { get; set; } = true;
public bool EnableOptimisticDirectExecution { get; set; } = ConfigurationManager.IsOptimisticDirectExecutionEnabled(defaultValue: true);

/// <summary>
/// Gets or sets the maximum number of items that can be buffered client side during
Expand Down
17 changes: 17 additions & 0 deletions Microsoft.Azure.Cosmos/src/Util/ConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ internal static class ConfigurationManager
/// </summary>
internal static readonly string PartitionLevelFailoverEnabled = "AZURE_COSMOS_PARTITION_LEVEL_FAILOVER_ENABLED";

/// <summary>
/// Environment variable name for overriding optimistic direct execution of queries.
/// </summary>
internal static readonly string OptimisticDirectExecutionEnabled = "AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED";

public static T GetEnvironmentVariable<T>(string variable, T defaultValue)
{
string value = Environment.GetEnvironmentVariable(variable);
Expand Down Expand Up @@ -72,5 +77,17 @@ public static bool IsPartitionLevelFailoverEnabled(
variable: ConfigurationManager.PartitionLevelFailoverEnabled,
defaultValue: defaultValue);
}

/// <summary>
/// Gets the boolean value indicating whether optimistic direct execution is enabled based on the environment variable override.
/// </summary>
public static bool IsOptimisticDirectExecutionEnabled(
bool defaultValue)
{
return ConfigurationManager
.GetEnvironmentVariable(
variable: OptimisticDirectExecutionEnabled,
defaultValue: defaultValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,136 @@ public async Task TestClientDisableOdeDefaultValue()
bool success = bool.TryParse(properties.QueryEngineConfiguration[ClientDisableOptimisticDirectExecution].ToString(), out bool clientDisablOde);
Assert.IsTrue(success, $"Parsing must succeed. Value supplied '{ClientDisableOptimisticDirectExecution}'");
Assert.IsFalse(clientDisablOde);
}

[TestMethod]
public async Task TestOdeEnvironmentVariable()
{
QueryRequestOptions options = new QueryRequestOptions();
Assert.IsTrue(options.EnableOptimisticDirectExecution);

foreach ((string name, string value, bool expectedValue) in new[]
{
// Environment variables are case insensitive in windows
("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", "true", true),
("AZURE_COSMOS_optimistic_direct_execution_enabled", "True", true),
("azure_cosmos_optimistic_direct_execution_enabled", "TRUE", true),
("Azure_Cosmos_Optimistic_Direct_Execution_Enabled", "truE", true),
("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", "false", false),
("AZURE_COSMOS_optimistic_direct_execution_enabled", "False", false),
("azure_cosmos_optimistic_direct_execution_enabled", "FALSE", false),
("Azure_Cosmos_Optimistic_Direct_Execution_Enabled", "false", false),
("Azure_Cosmos_Optimistic_Direct_Execution_Enabled", string.Empty, true),
(nameof(QueryRequestOptions.EnableOptimisticDirectExecution), "false", true),
(nameof(QueryRequestOptions.EnableOptimisticDirectExecution), null, true),
("enableode", "false", true)
})
{
try
{
// Test new value
Environment.SetEnvironmentVariable(name, value);
QueryRequestOptions options2 = new QueryRequestOptions();
bool areEqual = expectedValue == options2.EnableOptimisticDirectExecution;
Assert.IsTrue(areEqual, $"EnvironmentVariable:'{name}', value:'{value}', expected:'{expectedValue}', actual:'{options2.EnableOptimisticDirectExecution}'");
}
finally
{
// Remove side effects.
Environment.SetEnvironmentVariable(name, null);
}
}

foreach (string value in new[]
{
"'",
"-",
"asdf",
"'true'",
"'false'"
})
{
bool receivedException = false;
try
{
// Test new value
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", value);
QueryRequestOptions options2 = new QueryRequestOptions();
}
catch(FormatException fe)
{
Assert.IsTrue(fe.ToString().Contains($@"String '{value}' was not recognized as a valid Boolean."));
receivedException = true;
}
finally
{
// Remove side effects.
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", null);
}

Assert.IsTrue(receivedException, $"Expected exception was not received for value '{value}'");
}

await this.TestQueryExecutionUsingODEEnvironmentVariable(
environmentVariableValue: "false",
expectODEPipeline: false);

await this.TestQueryExecutionUsingODEEnvironmentVariable(
environmentVariableValue: "true",
expectODEPipeline: true);
}

private async Task TestQueryExecutionUsingODEEnvironmentVariable(string environmentVariableValue, bool expectODEPipeline)
{
IReadOnlyList<int> empty = new List<int>(0);
IReadOnlyList<int> first5Integers = Enumerable.Range(0, 5).ToList();
IReadOnlyList<int> first7Integers = Enumerable.Range(0, NumberOfDocuments).ToList();
IReadOnlyList<int> first7IntegersReversed = Enumerable.Range(0, NumberOfDocuments).Reverse().ToList();

try
{
// Test query execution using environment variable
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", environmentVariableValue);
PartitionKey partitionKeyValue = new PartitionKey("/value");
List<DirectExecutionTestCase> singlePartitionContainerTestCases = new List<DirectExecutionTestCase>()
{
CreateInput(
query: $"SELECT TOP 5 VALUE r.numberField FROM r ORDER BY r.{PartitionKeyField}",
expectedResult: first5Integers,
partitionKey: partitionKeyValue,
enableOptimisticDirectExecution: null, // Uses environment variable
pageSizeOptions: PageSizeOptions.NonGroupByAndNoContinuationTokenPageSizeOptions,
expectedPipelineType: expectODEPipeline ? TestInjections.PipelineType.OptimisticDirectExecution : TestInjections.PipelineType.Passthrough),
CreateInput(
query: $"SELECT TOP 5 VALUE r.numberField FROM r ORDER BY r.{PartitionKeyField}",
expectedResult: first5Integers,
partitionKey: partitionKeyValue,
enableOptimisticDirectExecution: false, // Overrides environment variable
pageSizeOptions: PageSizeOptions.NonGroupByAndNoContinuationTokenPageSizeOptions,
expectedPipelineType: TestInjections.PipelineType.Passthrough),
CreateInput(
query: $"SELECT TOP 5 VALUE r.numberField FROM r ORDER BY r.{PartitionKeyField}",
expectedResult: first5Integers,
partitionKey: partitionKeyValue,
enableOptimisticDirectExecution: true, // Overrides environment variable
pageSizeOptions: PageSizeOptions.NonGroupByAndNoContinuationTokenPageSizeOptions,
expectedPipelineType: TestInjections.PipelineType.OptimisticDirectExecution),
};

IReadOnlyList<string> documents = CreateDocuments(NumberOfDocuments, PartitionKeyField, NumberField, NullField);

await this.CreateIngestQueryDeleteAsync(
ConnectionModes.Direct | ConnectionModes.Gateway,
CollectionTypes.SinglePartition,
documents,
(container, documents) => RunTests(singlePartitionContainerTestCases, container),
"/" + PartitionKeyField);
}
finally
{
// Attempt to protect other ODE tests from side-effects in case of test failure.
Environment.SetEnvironmentVariable("AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED", null);
}
}

private static async Task RunTests(IEnumerable<DirectExecutionTestCase> testCases, Container container)
Expand All @@ -536,9 +666,13 @@ private static async Task RunTests(IEnumerable<DirectExecutionTestCase> testCase
{
MaxItemCount = pageSize,
PartitionKey = testCase.PartitionKey,
EnableOptimisticDirectExecution = testCase.EnableOptimisticDirectExecution,
TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, new TestInjections.ResponseStats())
};
};

if(testCase.EnableOptimisticDirectExecution.HasValue)
{
feedOptions.EnableOptimisticDirectExecution = testCase.EnableOptimisticDirectExecution.Value;
}

List<CosmosElement> items = await RunQueryAsync(
container,
Expand Down Expand Up @@ -600,7 +734,7 @@ private static DirectExecutionTestCase CreateInput(
string query,
IReadOnlyList<int> expectedResult,
PartitionKey? partitionKey,
bool enableOptimisticDirectExecution,
bool? enableOptimisticDirectExecution,
int[] pageSizeOptions,
TestInjections.PipelineType expectedPipelineType)
{
Expand All @@ -612,15 +746,15 @@ private readonly struct DirectExecutionTestCase
public string Query { get; }
public IReadOnlyList<int> ExpectedResult { get; }
public PartitionKey? PartitionKey { get; }
public bool EnableOptimisticDirectExecution { get; }
public bool? EnableOptimisticDirectExecution { get; }
public int[] PageSizeOptions { get; }
public TestInjections.PipelineType ExpectedPipelineType { get; }

public DirectExecutionTestCase(
string query,
IReadOnlyList<int> expectedResult,
PartitionKey? partitionKey,
bool enableOptimisticDirectExecution,
bool? enableOptimisticDirectExecution,
int[] pageSizeOptions,
TestInjections.PipelineType expectedPipelineType)
{
Expand Down
15 changes: 15 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ Preview features are treated as a separate branch and will not be included in th
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### <a name="3.39.0-preview.1"/> [3.39.0-preview.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.39.0-preview.1) - 2024-02-02
### <a name="3.38.1"/> [3.38.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.38.1) - 2024-02-02

#### Fixed
- [4294](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/4294) DisableServerCertificateValidation: Fixes Default HttpClient to honor DisableServerCertificateValidation (#4294)

#### Added
- [4299](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/4299) Query: Adds environment variable for overriding EnableOptimisticDirectExecution default (#4299)
> Note: This change provides another way to manage the upgrade to `3.38`. It provides an option to avoid potential disruption due to the breaking change (see the note below) if only config deployment is preferred, instead of any explicit code modification.
> With this change, users can set the environment variable AZURE_COSMOS_OPTIMISTIC_DIRECT_EXECUTION_ENABLED to false in their production environments while upgrading from previous minor version (`3.37` or below) to `3.38.1` (or above).
> This will signal the SDK to disable Optimistic Direct Execution by default.
> Once the environment is fully upgraded to the target version, the environment variable can be removed (or set to true) to enable ODE.
> It is recommended that the environment variable is used only to manage the upgrade and removed once the deployment is complete.
> Please note that environment variable acts as the override only for choosing the default value. If the code explicitly modifies the setting, that value will be honored during actual operations.

### <a name="3.39.0-preview.0"/> [3.39.0-preview.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.39.0-preview.0) - 2024-01-31

#### Added
Expand Down
Loading