Skip to content

Integrate Stored Procedure and Query Plan request routing to Gateway V2 endpoint#47759

Open
jeet1995 wants to merge 90 commits into
Azure:mainfrom
jeet1995:AzCosmos_GatewayV2_QueryPlanSupport
Open

Integrate Stored Procedure and Query Plan request routing to Gateway V2 endpoint#47759
jeet1995 wants to merge 90 commits into
Azure:mainfrom
jeet1995:AzCosmos_GatewayV2_QueryPlanSupport

Conversation

@jeet1995

@jeet1995 jeet1995 commented Jan 21, 2026

Copy link
Copy Markdown
Member

Summary

This PR integrates Query Plan and Stored Procedure request routing into the Gateway V2 thin-client (proxy) path, adds the RNTBD protocol surface the proxy needs to generate a query plan, and deserializes the proxy-generated query plan back into the client query pipeline. It also fixes a thin-client query-plan error-status regression and a hybrid/full-text diagnostics gap, and ships an oracle-style E2E suite that validates thin-client parity against Direct TCP.

Production changes (azure-cosmos)

RNTBD protocol surface (Gateway V2 proxy)

  • RntbdConstants.java — new QueryPlan operation type (0x0042) and two new request headers: SupportedQueryFeatures (0x00FF, String) and QueryVersion (0x0100, SmallString). IDs match the server-side proxy.
  • RntbdRequestHeaders.java — populate the SupportedQueryFeatures and QueryVersion RNTBD tokens from their HTTP-header equivalents so the proxy can extract them from the RNTBD body.
  • RntbdRequestFrame.java — wire the new QueryPlan operation type onto the request frame.

Query-plan routing & deserialization

  • QueryPlanRetriever.java — advertise CountIf in SUPPORTED_QUERY_FEATURES; route getQueryPlanThroughGatewayAsync through thin-client mode and pass the partitionKeyDefinition; defense-in-depth guard that converts a non-2xx / malformed query-plan response into a clean 400 instead of a leaked exception.
  • PartitionedQueryExecutionInfo.java — thin-client deserialization overload that accepts the partition-key definition (and response timeline), used to construct the query pipeline from a proxy-generated query plan.
  • QueryInfo.javagetGroupByAliasToAggregateType() and CountIf handling.
  • DocumentQueryExecutionContextFactory.java, IDocumentQueryClient.java — thread the partition-key definition into query-plan retrieval.

Stored-procedure routing

  • RxDocumentClientImpl.java, RxDocumentServiceRequest.java, ThinClientStoreModel.java — route stored-procedure execution through the Gateway V2 thin-client path.

Bug fix — thin-client query-plan error status (statusCode 0400)

  • RxGatewayStoreModel.validateOrThrow — a thin-client query-plan error frame (non-JSON, NUL-padded body) caused new CosmosError(body) to throw, which escaped before the intended throw dce and surfaced upstream as statusCode 0. It now falls back to a sanitized CosmosError, so the existing throw carries the real 400 with the server-provided substatus and message preserved. Strictly additive: 2xx responses and valid-JSON error bodies are byte-identical to before — only a previously-leaked exception path is corrected.

Diagnostics fix — hybrid / full-text

  • HybridSearchDocumentQueryExecutionContext.java — propagate the component-query client-side request statistics into the synthetic final FeedResponse, so endpoint diagnostics still show the core response path for RRF(...) / full-text queries.

Partition-key range routing

  • PartitionKeyInternalHelper.java — convert PartitionKeyInternal ranges into sorted EPK ranges for multi-range routing.

Test changes (azure-cosmos-tests)

The monolithic ThinClientE2ETest is replaced (−378) by a focused thin-client E2E suite (TestNG group thinclient, proxy :10250):

Test class Coverage
ThinClientQueryE2ETest 84 oracle-style tests — query parity, endpoint diagnostics, full-text, hybrid, vector, continuation draining
ThinClientChangeFeedE2ETest forFullRange(), forLogicalPartition(), incremental change feed
ThinClientPointOperationE2ETest CRUD + Patch, bulk, batch
ThinClientStoredProcedureE2ETest Stored procedure execute, no-PK error, PartitionKey.NONE
PartitionKeyInternalTest Client-side conversion of PartitionKeyInternal ranges to sorted EPK ranges
QueryPlanRetrieverSupportedFeaturesTest Advertised query-feature flags
ReadManyByPartitionKeyQueryPlanRoutingTest readMany query-plan routing
GatewayReadConsistencyStrategySpyWireTest Gateway read-consistency wire behavior

Plus: ThinClientTestBase / TestSuiteBase thin-client helpers, pom.xml thinclient profile wiring, and THINCLIENT_TEST_MATRIX.md coverage matrix.

Query-test methodology

ThinClientQueryE2ETest runs each query shape against the same seeded data through two paths:

  1. Direct TCP — baseline path to backend partition replicas.
  2. Gateway V2 thin client — system-under-test path through the thin-client proxy.

Assertions: (1) thin-client diagnostics include a request to the :10250 proxy endpoint, (2) Direct and thin-client result counts match, (3) result contents match — preserving order for ORDER BY queries and compared as sorted sets otherwise.

Assertion hardening (F1–F5)

  • F1 — strict 400 + unconditional :10250 endpoint assertion on invalid query (locks the statusCode 0400 fix above; no longer tolerates 0).
  • F2 — ordered-vs-sorted-set document-ID comparison (cross-partition order is only asserted for ORDER BY).
  • F3 — document-ID set equality and duplicate detection across drained continuation pages.
  • F41e-6 numeric tolerance for scalar and GROUP BY aggregates (avoids SUM/AVG float-formatting false mismatches).
  • F5 — validated vector / full-text / full-text-score-ranking / hybrid parity end-to-end (no proxy capability gap).

Query coverage validated

  • filters and projections
  • ORDER BY, DISTINCT, TOP, OFFSET / LIMIT
  • aggregates and GROUP BY
  • JOIN, EXISTS, LIKE, BETWEEN
  • string, math, type, array, and conditional functions
  • vector search, full-text ranking, hybrid RRF(...) queries
  • multi-range EPK routing
  • continuation-token draining (lowered page size)

All SDK Contribution checklist:

  • The pull request does not introduce [breaking changes]
  • CHANGELOG is updated for new features, bug fixes or other significant changes.
  • I have read the contribution guidelines.

Testing Guidelines

  • Pull request includes test coverage for the included changes.

@jeet1995

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jeet1995 jeet1995 changed the title Az cosmos gateway v2 query plan support [Gateway V2 / DO NOT MERGE]: Integrate Stored Procedure and Query Plan request routing to a Gateway V2 endpoint. Jan 29, 2026
@jeet1995

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jeet1995

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jeet1995 jeet1995 changed the title [Gateway V2 / DO NOT MERGE]: Integrate Stored Procedure and Query Plan request routing to a Gateway V2 endpoint. [Gateway V2][DO NOT MERGE]: Integrate Stored Procedure and Query Plan request routing to a Gateway V2 endpoint. Jan 30, 2026

@xinlian12 xinlian12 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks

@FabianMeiswinkel FabianMeiswinkel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - Thanks

…readiness probe for thin-client-default-on

- Remove the QueryPlan exemption in assertThinClientEndpointUsed: when ThinClient is
  opted in with HTTP/2 enabled, QueryPlan calls MUST also route to Gateway V2 (:10250),
  matching production default DEFAULT_THINCLIENT_QUERY_PLAN_ENABLED=true.
- Restore public static visibility on ThinClientTestBase.assertThinClientEndpointUsed /
  assertGatewayEndpointUsed so cross-package static imports (CosmosMultiHashTest) compile.
- Add OWNER_RESOURCE_NOT_EXISTS (subStatus 1003) to the retryable NOTFOUND allowlist in
  TestSuiteBase.isRetryableCollectionReadinessFailure. With thin-client default-on the
  beforeSuite readability probe (a QueryPlan) routes through GW V2; a freshly-created
  container not yet propagated to a secondary region returns 404/1003, which must be
  treated as a transient readiness failure instead of cascade-skipping the suite.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - spark

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - kafka

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

2 similar comments
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Validate the COSMOS.THINCLIENT_QUERY_PLAN_ENABLED sysprop/env kill-switch
in both directions:
- Unit: new case in ReadManyByPartitionKeyQueryPlanRoutingTest asserts
  QueryPlan is forced to Gateway V1 (useGatewayMode=true) when the flag
  is disabled, even with thin-client eligible.
- E2E: make TestSuiteBase.assertThinClientEndpointUsed flag-aware so
  QueryPlan endpoint assertions flip based on the live-read flag while
  data operations continue to route to the thin-client endpoint.

Both scenarios verified green (unit 3/3; E2E 112/112, oracle:true for
flag ON and flag OFF).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - kafka

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - spark

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

2 similar comments
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - spark

@jeet1995

jeet1995 commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - kafka

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

2 similar comments
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

jeet1995 added a commit to jeet1995/azure-sdk-for-java that referenced this pull request Jul 8, 2026
…zure#47759 merge

The Azure#47759 merge conflict resolution kept HEAD's short-circuit-wait loop
(which calls isAnyRegionShortCircuitedForPartition) but dropped the method
definition. Recovered from probe tip 42c2c7d and re-inserted.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jeet1995 and others added 2 commits July 8, 2026 20:27
ThinClientTestBase teardown unconditionally cleared the
COSMOS.THINCLIENT_ENABLED system property. Since Configs.isThinClientEnabled()
reads the property lazily per client build, a ThinClientTestBase subclass
running before a property-dependent class inherited from main (e.g.
CosmosMultiHashTest, ThinClientQueryE2ETest) in the same JVM wiped the ambient
-DCOSMOS.THINCLIENT_ENABLED=true flag supplied by the thin-client CI lane.
Later clients then built with thin client disabled and routed to :443,
breaking the :10250 thin-client endpoint assertions.

Save the prior value on enable and restore it on teardown (clear only when it
was originally absent), mirroring CosmosConsistencyOverrideValidationTest's
restoreSystemProperty pattern. Helpers changed from static to instance so the
saved value is per-instance, avoiding races across TestNG factory instances.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…stBase; revert workflow tests to main

ThinClientTestBase no longer sets/clears COSMOS.THINCLIENT_ENABLED per class. The 'thinclient' Maven lane already sets THINCLIENT_ENABLED=true and HTTP2_ENABLED=true JVM-wide via failsafe systemPropertyVariables, and all thin classes run only in that lane (groups={thinclient}). The prior per-class clearProperty in @afterclass wiped the ambient -D for later byte-identical-to-main classes in the same JVM, mis-routing requests to :443. Relying on the lane flag (matching ThinClientQueryE2ETest) removes that footgun.

Also revert CustomerWorkflowHighE2ETimeoutTest and CustomerWorkflowPartitionLevelCircuitBreakerTest to upstream/main (availability-strategy threshold stays 100ms), since this PR requires no changes there.

Verified locally (AZURE_TEST_MODE=LIVE, -Pthinclient,query,consistency-overrides): 234 passed, 0 failures/skips; QueryPlan routes to :10250.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jeet1995

jeet1995 commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - tests

@jeet1995

jeet1995 commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - spark

@jeet1995

jeet1995 commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

/azp run java - cosmos - kafka

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

2 similar comments
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants