-
Notifications
You must be signed in to change notification settings - Fork 535
[Internal] Thin Client Integration: Adds changefeed support in thinclient mode #5720
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -552,31 +552,54 @@ internal static bool IsStoredProcedureCrudOperation( | |
| operationType != Documents.OperationType.ExecuteJavaScript; | ||
| } | ||
|
|
||
| internal static bool IsOperationSupportedByThinClient(DocumentServiceRequest request) | ||
| { | ||
| // Document operations | ||
| if (request.ResourceType == ResourceType.Document | ||
| && (request.OperationType == OperationType.Batch | ||
| || request.OperationType == OperationType.Patch | ||
| || request.OperationType == OperationType.Create | ||
| || request.OperationType == OperationType.Read | ||
| || request.OperationType == OperationType.Upsert | ||
| || request.OperationType == OperationType.Replace | ||
| || request.OperationType == OperationType.Delete | ||
| || request.OperationType == OperationType.Query | ||
| || request.OperationType == OperationType.QueryPlan)) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // Stored Procedure execution | ||
| if (request.ResourceType == ResourceType.StoredProcedure | ||
| && request.OperationType == OperationType.ExecuteJavaScript) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| internal static bool IsOperationSupportedByThinClient(DocumentServiceRequest request) | ||
| { | ||
| // Document operations | ||
| if (request.ResourceType == ResourceType.Document | ||
| && (request.OperationType == OperationType.Batch | ||
| || request.OperationType == OperationType.Patch | ||
| || request.OperationType == OperationType.Create | ||
| || request.OperationType == OperationType.Read | ||
| || request.OperationType == OperationType.Upsert | ||
| || request.OperationType == OperationType.Replace | ||
| || request.OperationType == OperationType.Delete | ||
| || request.OperationType == OperationType.Query | ||
| || request.OperationType == OperationType.QueryPlan)) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // LatestVersion (Incremental) ChangeFeed on documents. | ||
| // AllVersionsAndDeletes (FullFidelity) is excluded because it requires | ||
| // split-handling logic in Compute Gateway (UseGatewayMode is set by ChangeFeedModeFullFidelity). | ||
| if (request.ResourceType == ResourceType.Document | ||
| && request.OperationType == OperationType.ReadFeed | ||
| && GatewayStoreModel.IsLatestVersionChangeFeedRequest(request)) | ||
|
aavasthy marked this conversation as resolved.
|
||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // Stored Procedure execution | ||
| if (request.ResourceType == ResourceType.StoredProcedure | ||
| && request.OperationType == OperationType.ExecuteJavaScript) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Determines if the request is a LatestVersion (Incremental) change feed request that can | ||
| /// be routed to the thin client. Returns true only when the A-IM header is exactly | ||
| /// <c>HttpConstants.A_IMHeaderValues.IncrementalFeed</c>. Any other value — including | ||
| /// Full-Fidelity Feed (AllVersionsAndDeletes) or an unknown future mode — falls back to | ||
| /// Compute Gateway so that new modes are not accidentally routed to the thin client. | ||
| /// </summary> | ||
| internal static bool IsLatestVersionChangeFeedRequest(DocumentServiceRequest request) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Recommendation · Correctness: Fragile Negation Logic Prefer positive matching for This method checks Why it matters: If a third change feed mode is added with a new A-IM value (e.g., Currently there are only two A-IM values ( Suggested change: return string.Equals(aImHeaderValue, HttpConstants.A_IMHeaderValues.IncrementalFeed, StringComparison.OrdinalIgnoreCase);
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Switched to positive matching in commit
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟢 Suggestion · Naming: Method Name vs. Implementation Mismatch Method name implies positive check but implementation is negative
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good suggestion, Possibly IsFullFidelityChangeFeedRequest will be better given the functionality
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the switch to positive matching ( |
||
| { | ||
| string aImHeaderValue = request.Headers[HttpConstants.HttpHeaders.A_IM]; | ||
|
aavasthy marked this conversation as resolved.
|
||
| return string.Equals(aImHeaderValue, HttpConstants.A_IMHeaderValues.IncrementalFeed, StringComparison.OrdinalIgnoreCase); | ||
| } | ||
| private async Task<AccountProperties> GetDatabaseAccountPropertiesAsync() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,7 @@ public class CosmosItemThinClientTests | |
| [TestInitialize] | ||
| public async Task TestInitAsync() | ||
| { | ||
| Environment.SetEnvironmentVariable(ConfigurationManager.ThinClientModeEnabled, "True"); | ||
| Environment.SetEnvironmentVariable(ConfigurationManager.ThinClientModeEnabled, "True"); | ||
| this.connectionString = Environment.GetEnvironmentVariable("COSMOSDB_THINCLIENT"); | ||
|
|
||
| if (string.IsNullOrEmpty(this.connectionString)) | ||
|
|
@@ -1354,6 +1354,52 @@ public async Task TestThinClientQueryPlanMultiPartitionFanout() | |
| } | ||
| } | ||
|
|
||
| [TestMethod] | ||
| [TestCategory("ThinClient")] | ||
| public async Task TestThinClientChangeFeedLatestVersionAsync() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟢 Suggestion · Testing: Add Emulator Test for AllVersionsAndDeletes Consider adding a companion emulator test for FullFidelity change feed This test verifies LatestVersion change feed routes through thin client by checking Unit tests already cover the FullFidelity → gateway path, so this is a nice-to-have for integration confidence. |
||
| { | ||
| // Arrange: | ||
| string pk = "pk_changefeed"; | ||
| List<TestObject> items = this.GenerateItems(pk).Take(10).ToList(); | ||
| List<TestObject> createdItems = await this.CreateItemsSafeAsync(items); | ||
|
|
||
| Assert.IsTrue(createdItems.Count > 0, "At least one item must be created for the change feed test."); | ||
|
|
||
| // Act: Read change feed using LatestVersion mode | ||
| List<TestObject> changeFeedResults = new List<TestObject>(); | ||
| FeedIterator<TestObject> changeFeedIterator = this.container.GetChangeFeedIterator<TestObject>( | ||
| ChangeFeedStartFrom.Beginning(), | ||
| ChangeFeedMode.LatestVersion, | ||
| new ChangeFeedRequestOptions() | ||
| { | ||
| PageSizeHint = 10 | ||
| }); | ||
|
|
||
| while (changeFeedIterator.HasMoreResults) | ||
| { | ||
| FeedResponse<TestObject> response = await changeFeedIterator.ReadNextAsync(); | ||
|
|
||
| if (response.StatusCode == HttpStatusCode.NotModified) | ||
| { | ||
| break; | ||
| } | ||
|
|
||
| string diagnostics = response.Diagnostics.ToString(); | ||
| Assert.IsTrue(diagnostics.Contains("|F4"), "Diagnostics User Agent should contain '|F4' for ThinClient change feed"); | ||
|
|
||
| changeFeedResults.AddRange(response); | ||
| } | ||
|
|
||
| // Assert: Verify all created items appear in the change feed | ||
| Assert.IsTrue(changeFeedResults.Count >= createdItems.Count, | ||
| $"Change feed should return at least {createdItems.Count} items but got {changeFeedResults.Count}."); | ||
|
|
||
| HashSet<string> createdIds = new HashSet<string>(createdItems.Select(i => i.Id)); | ||
| HashSet<string> changeFeedIds = new HashSet<string>(changeFeedResults.Select(i => i.Id)); | ||
| Assert.IsTrue(createdIds.IsSubsetOf(changeFeedIds), | ||
| "All created items should appear in the change feed results."); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// DelegatingHandler that intercepts HTTP requests and can inject faults | ||
| /// </summary> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.