Gate thin-client (Gateway V2) routing behind an endpoint connectivity probe when COSMOS.THINCLIENT_ENABLED is unset#49437
Open
jeet1995 wants to merge 149 commits into
Open
Conversation
… QueryPlan proxy routing Add RNTBD token mappings for x-ms-cosmos-supported-query-features (0x002B) and x-ms-cosmos-query-version (0x002C) so the thin client proxy can read these values from the RNTBD body when processing QueryPlan requests. Previously these headers were only set as HTTP headers by QueryPlanRetriever and were lost when QueryPlan was routed through the proxy path, since ThinClientStoreModel serializes requests as RNTBD (not HTTP headers). IDs match server-side proxy definitions per ADO PR 1982503. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add testThinClientChangeFeedFullRange covering FeedRange.forFullRange() across multiple partition keys, and testThinClientChangeFeedPartitionKey covering FeedRange.forLogicalPartition with exact doc count + PK validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Documents all 59 thin client E2E tests across query (50), point operations (3), change feed (3), and stored procedures (3) with SQL, query features covered, and known account-side blockers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… QueryPlan proxy routing Add RNTBD token mappings for x-ms-cosmos-supported-query-features (0x00F0) and x-ms-cosmos-query-version (0x00F1) so the thin client proxy can read these values from the RNTBD body when processing QueryPlan requests. IDs are provisional (0x00F0, 0x00F1) — must be coordinated with server-side proxy team. See ADO PR 1982503 for the proxy-side design. Note: The design doc listed 0x002B/0x002C but those are already assigned to PartitionKey/PartitionKeyRangeId in the Java SDK. Using 0x00F0/0x00F1 to avoid ID collision until final server-side IDs are assigned. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…BD instructions - Fix testGetCurrentDateTime: assert ISO 8601 format instead of exact match (gateway and proxy return slightly different timestamps) - Add DefaultAzureCredential support via COSMOS.USE_AAD_AUTH system property for accounts with disableLocalAuth=true - Add RNTBD class reference as .github/instructions/rntbd.instructions.md - Add pom.xml system properties for THINCLIENT_ENABLED, HTTP2_ENABLED, USE_AAD_AUTH - Add beforeSuiteReuse mode for degraded accounts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Switch baseline from Gateway V1 to Direct TCP to avoid JVM config interference (THINCLIENT_ENABLED/HTTP2_ENABLED affect Gateway V1) - Assert :10250 endpoint only on Gateway V2 results (not baseline) - Rename helpers: assertDirectAndThinClientMatch (was gateway) - Document seedTestData schema in Javadoc - Remove 'Expected to fail' comments (account has vector search enabled) - Clean up class/method Javadoc Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
xinlian12
reviewed
Jul 10, 2026
xinlian12
reviewed
Jul 10, 2026
Member
|
✅ Review complete (46:59) Posted 6 inline comment(s). Steps: ✓ context, correctness, cross-sdk, design, history, past-prs, synthesis, test-coverage |
…ffix Fold ThinClient into generateHttp2OptedInUserAgentIfRequired so the helper dynamically mirrors production feature-flag suffixing, and remove a double-wrap of directClientUserAgent (already suffixed at construction). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
On the implicit/probe path (COSMOS.THINCLIENT_ENABLED unset), thin-client routing depends on the endpoint probe greenlighting all current regions. Under fault injection the probe is not guaranteed to converge, so requests may legitimately fall back to Gateway V1 (:443). Assert thin-client routing only when thin-client is explicitly opted in (THINCLIENT_ENABLED=true), the sole config where routing is deterministic because the probe is bypassed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…parsing, probe-client close, fire-and-forget probe cycle, single-flight tests - Configs: parse COSMOS.THINCLIENT_ENABLED via explicit true/false whitelist (parseTriStateThinClientEnabled); any other value logs a warning and is treated as unset (null -> probe-gated) instead of Boolean.parseBoolean silently collapsing every non-"true" string to a hard opt-out. - GlobalEndpointManager: close() now cancels the in-flight probe-cycle subscription and closes the EndpointProbeClient so a stale cycle drops its result. Probe cycle is fired fire-and-forget on force-refresh and topology refresh so init()/cross-region retry never block on the probe; routing stays on Gateway V1 until the probe proves the proxy endpoints. - Tests: add ConfigsTests.thinClientEnabledInvalidValueTreatedAsUnset and two EndpointProbeClientTests covering single-flight overlap skip and closed-mid-cycle result-drop (gate stays conservative). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Member
Author
|
/azp run java - cosmos - kafka |
Member
Author
|
/azp run java - cosmos - spark |
Member
Author
|
/azp run java - cosmos - tests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
2 similar comments
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Azure Pipelines successfully started running 1 pipeline(s). |
…into jeet1995/thin-client-probe-flow
useThinClient() now reflects config-eligibility only; the test must gate on actual per-request routing (read locations + probe/opt-in) to match where the query lands. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Member
Author
|
/azp run java - cosmos - tests |
Member
Author
|
/azp run java - cosmos - spark |
Member
Author
|
/azp run java - cosmos - kafka |
|
Azure Pipelines successfully started running 1 pipeline(s). |
2 similar comments
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Azure Pipelines successfully started running 1 pipeline(s). |
…ed() - Gate probe wiring in RxDocumentClientImpl on canThinClientBeUsed() so an explicit THINCLIENT_ENABLED=true still wires the probe (routing bypasses it), covering true->null runtime transitions. Removed dead canThinClientBeImplicitlyEnabled() from ThinClientConnectivityConfig and updated javadoc/comments/pom profile references accordingly. - Strengthen single-flight test with a post-release third cycle probing a new region to confirm the guard releases correctly. - Skip connectivity-probe requests in GatewayReadConsistencyStrategySpyWireTest request selectors: with the probe now wired under explicit enablement, its bodyless POST /connectivity-probe to :10250 was being captured by the V2 selectors, causing an NPE in collectHttpBody. The spy now filters probe traffic and selects the actual data request. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Member
Author
|
/azp run java - cosmos - tests |
Member
Author
|
/azp run java - cosmos - spark |
Member
Author
|
/azp run java - cosmos - kafka |
|
Azure Pipelines successfully started running 1 pipeline(s). |
2 similar comments
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Azure Pipelines successfully started running 1 pipeline(s). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Gateway V2 (ThinClient) is the new Compute-hosted data plane for Cosmos DB. To roll it out safely the Java SDK needs a user-transparent way to route eligible data-plane and QueryPlan requests to ThinClient only once the proxy is proven reachable (or the user explicitly opts in) — without user-visible errors or per-request overhead. Today the SDK has no client-side reachability signal which this PR aims to solve:
COSMOS.THINCLIENT_ENABLEDan explicit tri-state:true= hard opt-in (probe bypassed),false= hard opt-out, unset = probe-gated (route to Gateway V2 only once the connectivity probe greenlights the proxy, else Gateway V1). Unset does not default routing on.EndpointProbeClient) thatPOSTs to/connectivity-probeover the thin-client HTTP/2 transport every topology refresh. The verdict feeds the routing gate viaGlobalEndpointManager.getProxyProbeDecision().Key invariants:
false(empty endpoint set), so a slow/failing first probe never pushes traffic onto an unproven proxy.THINCLIENT_ENABLED=trueskips the probe gate for routing; the probe governs only the implicit path.onErrorResume.getProxyProbeDecision()istrueonly when every known region has a proven (HTTP 200) probe,falsewhen a known region is unproven/non-200,nullbefore any verdict. On the implicit path bothfalseandnullpin to Gateway V1; a region flips healthy on its first 200 — no thresholds.provenHealthyEndpoints.containsAll(currentEndpoints)against a volatile snapshot.Call sequence
sequenceDiagram autonumber participant App as User App participant Client as CosmosClient<br/>(RxDocumentClientImpl) participant GEM as GlobalEndpointManager participant Probe as EndpointProbeClient participant Proxy as ThinClient<br/>(Gateway V2) participant V1 as Gateway V1<br/>(fallback) rect rgba(200,220,255,0.25) Note over App,Probe: Bootstrap (one-time) App->>Client: new CosmosClient(...) Client->>Client: canThinClientBeUsed() (HTTP/2 + Gateway mode, not opted out) alt thin-client usable Client->>GEM: setThinClientHttpClient(...) GEM->>Probe: new EndpointProbeClient(httpClient) Note over Probe: wired even for explicit true — routing bypasses it on that path else not usable Note over Client,Probe: probe not wired end end rect rgba(200,255,210,0.25) Note over GEM,Proxy: Topology refresh (every tick) GEM->>GEM: refreshLocationPrivateAsync() → runThinClientProbeCycleMono() GEM->>Probe: runProbeCycle(delta endpoints) par Per new endpoint Probe->>Proxy: POST /connectivity-probe (HTTP/2) Proxy-->>Probe: 200 (or error/timeout) end Probe->>Probe: applyCycleResult() — cache proven regions Note right of Probe: all regions 200 → true — any unproven/non-200 → false end rect rgba(255,235,200,0.25) Note over App,V1: Data-plane / QueryPlan request App->>Client: readItem(...) / queryItems(...) Client->>GEM: getProxyProbeDecision() GEM-->>Client: true / false / null alt usable && hasThinClientReadLocations && eligible && (explicitOptIn || decision==true) Client->>Proxy: route through Gateway V2 else gate failed (false/null, implicit path) Client->>V1: route through Gateway V1 end Client-->>App: response (transparent fallback) endConfiguration
COSMOS.THINCLIENT_ENABLEDConfigs.isThinClientEnabled()). Unset ⇒ probe-gated;true⇒ opt-in bypassing the probe;false⇒ never route thin-client.This PR only changes the semantics of the master switch; HTTP/2 (
COSMOS.HTTP2_ENABLED) + GATEWAY mode remain the transport prerequisite./connectivity-probeis a fixed proxy contract — no separate kill-switch, threshold, or probe-path property.