[Internal] DTS: Adds session-token support and typed response deserialization for transactions#5885
Conversation
Additive pre-public preview changes to the distributed transaction client surface. No existing public API is broken. Per-operation session token - Adds `DistributedTransactionRequestOptions.SessionToken`, propagated into `DistributedTransactionOperation` (whitespace-only normalized to null) and serialized per-operation in the request body, matching the coordinator's wire contract. - Tokens are frozen at request-build time and re-sent unchanged on retries to preserve idempotency. Typed response deserialization - Adds `DistributedTransactionResponse.GetOperationResultAtIndex<T>()` and the typed `DistributedTransactionOperationResult<T>` subclass, mirroring `TransactionalBatchResponse`. - Threads `CosmosSerializerCore` through both the normal and error-recovery result paths; throws `InvalidOperationException` if typed deserialization is requested without a serializer. Safe stream lifetime - `CosmosSerializer.FromStream<T>` disposes its input. Adds `CreateSnapshot(Stream)` which returns a fresh stream over the same bytes (zero-copy for plain `MemoryStream`; copy fallback otherwise), so the underlying `ResourceStream` survives repeated typed reads and direct indexer access. Docs and minor cleanup - Documents `ResourceStream` ownership/lifetime. - Adds isolation and typed-deserialization notes on `DistributedReadTransaction`. - Minor cleanup in `DistributedWriteTransactionCore`. Tests - Per-op session token wiring (present, absent, whitespace, multi-operation) in `DistributedTransactionCommitterTests`. - Typed deserialization, stream-lifetime safety, post-dispose behavior, and the null-serializer guard in `DistributedTransactionResponseTests`. Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
📝 Changelog reminder (non-blocking)This PR touches shipped source but does not appear to update the Touched (and missing entry for):
How to decideUse the rubric in
This check is non-blocking — merge is not gated on it. The |
NaluTripician
left a comment
There was a problem hiding this comment.
Looks good — approving. Implementation of the outbound session-token plumbing and the typed GetOperationResultAtIndex<T> / DistributedTransactionOperationResult<T> is correct, well-scoped, and well-tested. Nothing blocking from me.
A few non-blocking nits / follow-ups to consider:
- Read-op session-token coverage. All four new committer tests use
OperationType.Create, but the PR description leads with Read consistency as the primary use case. A singleDistributedReadTransactionCoretest that setsSessionTokenon a Read op and asserts it reaches the request body would close the most visible coverage gap. - Deserialization-failure path on
GetOperationResultAtIndex<T>. Happy path, no-body, no-serializer, OOB index, post-Dispose, and called-twice are all covered, but there's no test (or<exception>doc) for the case where the body JSON cannot be deserialized toT. Worth pinning the exception type with one test and an<exception>element on the XML doc. - Dispose hygiene in the new
DistributedTransactionResponseTests. Most of the new tests create aDistributedTransactionResponseand never dispose it, which is inconsistent with the dispose-specific tests in the same file and withIDisposablehygiene in general. Preferusing DistributedTransactionResponse response = ...across all the new ones. TestDocumentattribute mismatch. The test type uses[System.Text.Json.Serialization.JsonPropertyName], but the runtime serializer isCosmosJsonDotNetSerializer(Newtonsoft). The attributes are silently ignored — tests pass only because property casing happens to match. Either drop the attributes or switch to[Newtonsoft.Json.JsonProperty]so the intent is honest.DistributedTransactionOperationResult<T>.Resourcesetter. Currently{ get; set; }. Every other property on the base class is{ get; internal set; }— tightening this tointernal setwould match the existing pattern.- Redundant
ThrowIfDisposed()inGetOperationResultAtIndex<T>. The indexer call on the next line already does this check. Harmless, but worth either removing or leaving a one-line comment noting the outer call is deliberate. SessionTokendoc onDistributedTransactionRequestOptions. Doc requires{partitionKeyRangeId}:{lsn}format, but the SDK doesn't validate — would be helpful to call out that an invalid format will surface as a server-side error.
None of these block. Nice work.
kushagraThapar
left a comment
There was a problem hiding this comment.
Hi @Meghana-Palaparthi — thanks for this thorough PR. The implementation is correct, the snapshot-based multi-call story on GetOperationResultAtIndex<T> is genuinely better than the peer batch behavior, and @NaluTripician's prior approval covers the bulk of the correctness side cleanly.
I wanted to layer in one extra angle that we're explicitly trying to call out on every Cosmos PR going forward: supportability and long-term breaking-change risk for surfaces that lock in once #if INTERNAL lifts. Below are the three highest-leverage things that I think are worth thinking about before this preview eventually GAs — all of them are non-blocking, and several are one-line fixes today that would otherwise be breaking changes after release.
- M1 — DTS / non-DTS session-token plumbing convergence (inline on
DistributedTransactionRequestOptions.cs) — single highest 2-3-year cost decision in this PR. - M2 + M3 — public surface of
DistributedTransactionOperationResultdiverges fromTransactionalBatchOperationResultpeer;SubStatusCodeValueis the onlypublic uintsub-status in the SDK (inline onDistributedTransactionOperationResult.cs). - M4 — XML doc claims V1 session-token wire format; design-doc canonical is V2 (vector) (inline on
DistributedTransactionRequestOptions.cs).
Leaving this as a COMMENT review rather than an approval — @NaluTripician already has the correctness side covered; I'm just adding the supportability lens to the public record.
(We also have 8 minor + 9 nit items in our internal review notes — happy to surface any inline if helpful. Mainly: a typed IEnumerable<DistributedTransactionOperationResult<T>> projection, a [JsonExtensionData] forward-compat catch-all, decoupling C# names from wire field names via a private DTO, and a proposed extension to cosmosdb-design-docs/16-session-tokens.md covering DTS as the first surface using body-based session tokens.)
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
kushagraThapar
left a comment
There was a problem hiding this comment.
Thanks @Meghana-Palaparthi — really appreciate the quick turnaround on the doc fix and for opening #5896 to cleanly handle the public-surface / manual-deserialization work in a separate PR. Approving. 🙏
|
@copilot resolve the merge conflicts in this pull request |
Resolved the merge conflicts and merged latest |
Pull Request Template
Description
This pull request introduces several improvements and new features to the distributed transactions API in the Azure Cosmos DB SDK, with a focus on enhancing typed deserialization of operation results, streamlining session token handling, and improving documentation and usability. The most important changes are outlined below:
Typed Deserialization and Result Handling:
DistributedTransactionOperationResult<T>class, enabling easy access to deserialized resources from distributed transaction operations. This is returned by the newGetOperationResultAtIndex<T>(int index)method onDistributedTransactionResponse, which safely deserializes the resource body into the requested type without affecting the underlying stream. [1] [2]CreateSnapshotutility method to produce independent copies of resource streams, ensuring that repeated deserialization or direct stream access remain safe and side-effect free.Session Token Management:
SessionTokenproperty toDistributedTransactionRequestOptions, allowing each operation in a distributed transaction to specify its own session token for partition-level consistency. This is now set when constructing aDistributedTransactionOperation. [1] [2]API Usability and Documentation:
ResourceStreamproperty documentation to clarify ownership and correct usage patterns.Internal Consistency and Plumbing:
Minor Improvements:
CommitTransactionAsyncmethod'sCancellationTokenparameter optional for improved developer ergonomics.Type of change
Please delete options that are not relevant.
Closing issues
To automatically close an issue: closes #IssueNumber
Changelog
### Unreleasedinchangelog.mdfor the user-facing impact of this change.
documentation-only, test-only, CI / build-only, or a pure internal refactor
with no observable customer impact.
If the second box is checked, briefly justify here: