Skip to content

Change Feed Processor: Adds Lease container export support#5579

Merged
yash2710 merged 29 commits intomasterfrom
users/trivediyash/leaseExport
Apr 24, 2026
Merged

Change Feed Processor: Adds Lease container export support#5579
yash2710 merged 29 commits intomasterfrom
users/trivediyash/leaseExport

Conversation

@yash2710
Copy link
Copy Markdown
Contributor

@yash2710 yash2710 commented Jan 28, 2026

Description

This PR adds the ability to persist and restore in-memory ChangeFeed processor lease state via a MemoryStream. When a processor is built with WithInMemoryLeaseContainer(MemoryStream), the stream serves as both input and output: existing data in the stream initializes the lease container on startup, and the current lease state is automatically written back to the stream when the processor stops. This enables backup, restore, and restart scenarios for in-memory lease containers without requiring a Cosmos DB lease container.

API

public class ChangeFeedProcessorBuilder
{
    /// <summary>
    /// Uses an in-memory container to maintain state of the leases, optionally
    /// initialized from a MemoryStream containing previously persisted lease state.
    /// When the processor stops, the current lease state is automatically written
    /// back to the same stream.
    /// </summary>
    /// <param name="leaseState">
    /// A MemoryStream that serves as both input and output for lease state. The stream
    /// must be writable and expandable (e.g., new MemoryStream()). A fixed-size stream
    /// such as new MemoryStream(byte[]) will fail at shutdown if the serialized lease
    /// state exceeds the original buffer capacity. StopAsync must not be invoked
    /// concurrently from multiple threads.
    /// </param>
    public virtual ChangeFeedProcessorBuilder WithInMemoryLeaseContainer(
        MemoryStream leaseState);
}

Design Decisions

Single MemoryStream for Read and Write

  • The MemoryStream serves dual purpose: if it contains data on init, leases are deserialized from it. On StopAsync, current lease state is serialized back into the same stream.
  • This keeps the API surface minimal — one new method, no new types, no separate export/import calls.

Persist-First Shutdown Ordering

  • ChangeFeedProcessorCore.StopAsync calls storeManager.ShutdownAsync() before partitionManager.StopAsync().
  • If persistence fails, the exception surfaces immediately and partition shutdown is skipped (caller decides what to do). If persistence succeeds, partitions are stopped with the snapshot already durable.
  • Trade-off: checkpoint mutations produced during partition shutdown are not captured in the persisted snapshot. Acceptable because change-feed consumers are already required to be idempotent.

Stream Writer Correctness

  • DocumentServiceLeaseContainerInMemory.ShutdownAsync calls SetLength(serializedBytes.Length) before writing. If the supplied stream is not expandable and cannot hold the new payload, SetLength throws and the user's stream is left untouched — no partial-write corruption.
  • A failed resize surfaces as InvalidOperationException with a message pointing callers at new MemoryStream() instead of new MemoryStream(byte[]).

Automatic Persistence on Stop

  • Lease state is written to the stream inside the StopAsync flow, via a virtual ShutdownAsync() lifecycle hook on the internal DocumentServiceLeaseContainer base class, overridden only by the in-memory implementation.

Shared Serialization Format

  • Read and write paths both go through InMemoryLeaseJsonFormat, a single internal helper that owns encoding, buffer size, and JsonSerializer settings. This prevents silent drift between writer and reader.

Duplicate Lease Detection

  • DocumentServiceLeaseStoreManagerInMemory.DeserializeLeaseState fails fast with InvalidOperationException if the persisted state contains duplicate lease ids, rather than silently overwriting entries.

No Changes to Cosmos-Backed Leases

  • The Cosmos-backed lease container is unchanged. The ShutdownAsync base class method is a no-op for implementations that manage their own persistence.

In-Memory Only

  • This feature is scoped to in-memory lease containers. Cosmos-backed containers already persist leases in Cosmos DB and don't need this mechanism.

Usage Example

// First run — start with an empty, expandable stream
MemoryStream leaseState = new MemoryStream();

ChangeFeedProcessor processor = container
    .GetChangeFeedProcessorBuilder<MyDocument>("myProcessor", HandleChangesAsync)
    .WithInstanceName("instance-1")
    .WithInMemoryLeaseContainer(leaseState)
    .Build();

await processor.StartAsync();
// ... process changes ...
await processor.StopAsync();
// leaseState now contains the serialized lease state

// Save to file for later use
File.WriteAllBytes("leases.json", leaseState.ToArray());

// Later — restore from saved state.
// IMPORTANT: use an EXPANDABLE MemoryStream. `new MemoryStream(byte[])` is
// non-resizable and will throw at StopAsync if new state is larger than the
// original buffer. Always rehydrate by writing the bytes into a fresh,
// growable MemoryStream and resetting Position to 0.
byte[] savedState = File.ReadAllBytes("leases.json");
MemoryStream restoredState = new MemoryStream();
restoredState.Write(savedState, 0, savedState.Length);
restoredState.Position = 0;

ChangeFeedProcessor newProcessor = container
    .GetChangeFeedProcessorBuilder<MyDocument>("myProcessor", HandleChangesAsync)
    .WithInstanceName("instance-1")
    .WithInMemoryLeaseContainer(restoredState)
    .Build();

await newProcessor.StartAsync();
// Resumes processing from where it left off

Why not new MemoryStream(savedState)? That constructor returns a non-resizable stream backed by the supplied buffer. If the current lease state serializes to even one byte more than savedState.Length, StopAsync will fail — and because nothing fails at startup, the problem only shows up at shutdown in production. The Write + Position = 0 pattern above produces a resizable copy and avoids this class of bug entirely.

Test Coverage

Builder Tests (ChangeFeedProcessorBuilderTests)

  • WithInMemoryLeaseContainerWithStreamInitializesStoreCorrectly — Verifies leases are restored from a populated stream.
  • WithInMemoryLeaseContainerWithEmptyStreamInitializesEmptyStore — Empty stream creates an empty container.
  • WithInMemoryLeaseContainerWithEmptyArrayStreamInitializesEmptyStore — Covers the empty-array seed variant.
  • WithInMemoryLeaseContainerWithNullStreamThrows — Validates null argument handling.
  • WithInMemoryLeaseContainerWithStreamCannotCombineWithLeaseContainer — Prevents combining with Cosmos container.
  • WithInMemoryLeaseContainerWithStreamCannotCombineWithExistingInMemory — Prevents double in-memory configuration.
  • WithInMemoryLeaseContainerWithCorruptedStreamThrowsInvalidOperation — Malformed JSON surfaces as InvalidOperationException.
  • WithInMemoryLeaseContainer_FullLifecycle_RestoreProcessStopPersist — End-to-end restore → use → stop → re-persist.

In-Memory Container Tests (DocumentServiceLeaseContainerInMemoryTests)

  • ShutdownAsync_WithNoStream_IsNoOp — No-op when no stream is configured.
  • ShutdownAsync_WritesExpectedCount — Correct lease count serialized (parameterized: 0, 2).
  • ShutdownAsync_StreamPositionResetToZero — Stream position reset for consumers.
  • ShutdownAsync_WithNonEpkLease_StillSerializes — Non-EPK lease types persist correctly.
  • ShutdownAsync_WithDisposedStream_Throws — Disposed stream surfaces as InvalidOperationException.
  • ShutdownAsync_WithNonResizableStream_SameSizeData_WritesSuccessfully — Fixed buffer sized exactly right still works.
  • ShutdownAsync_WithNonResizableStream_LargerData_ThrowsInvalidOperation — Fixed buffer too small fails fast, before any partial write.
  • PersistThenDeserialize_RoundTrip_PreservesData — Full round-trip preserves LeaseToken, ContinuationToken, Owner, Properties (including unicode), FeedRange, and Timestamp.
  • PersistOverwritesPreviousStreamContent — Second persist replaces previous data (no stale trailing bytes).
  • Deserialize_DuplicateIds_Throws — Duplicate lease ids in persisted state fail fast.
  • Deserialize_LeavesStreamPositionAtZero — Reader resets stream position so subsequent writers see a fresh stream.

Processor Core Tests (ChangeFeedProcessorCoreTests)

  • StopAsync_CallsShutdownAsync — Verifies ShutdownAsync is invoked during stop.
  • StopAsync_WithInMemoryLeases_PersistsStateToStream — Persist-first ordering produces a populated stream.
  • StopAsync_WhenShutdownAsyncThrows_ExceptionPropagates — Persistence failure surfaces to the caller and skips partition shutdown.

Type of change

  • New feature (non-breaking change which adds functionality)

Closing issues

closes #5580

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

All good!

@yash2710 yash2710 changed the title Adds: Lease container export support Change Feed Processor: Adds Lease container export support Jan 28, 2026
@yash2710 yash2710 force-pushed the users/trivediyash/leaseExport branch from dce1b84 to f6b9083 Compare February 10, 2026 18:00
@kushagraThapar
Copy link
Copy Markdown
Member

I am curious if there are multiple version of leases present and if a customer tries to import v1 leases into a lease container where v2 leases are present? Is that a case in .NET SDK?
Also, what happens if existing leases are preserved and imported leases also have the same partitions as preserved leases, which ones take precedence?

@yash2710
Copy link
Copy Markdown
Contributor Author

Also, what happens if existing leases are preserved and imported leases also have the same partitions as preserved leases, which ones take precedence?

If there are existing leases, and the overwriteExisting flag is set to true, it would overwrite the preserved leases. The default value for overwriteExisting is false

@kushagraThapar
Copy link
Copy Markdown
Member

kushagraThapar commented Feb 19, 2026

Also, what happens if existing leases are preserved and imported leases also have the same partitions as preserved leases, which ones take precedence?

If there are existing leases, and the overwriteExisting flag is set to true, it would overwrite the preserved leases. The default value for overwriteExisting is false

makes sense, I am curious about the case when overwriteExisting is false and existing leases have the partition which importing leases also have, is there conflict resolution happening to decide which lease to take for the specific partition?

@yash2710 yash2710 force-pushed the users/trivediyash/leaseExport branch from 9f631f1 to cc61cc3 Compare March 2, 2026 23:08
@yash2710 yash2710 force-pushed the users/trivediyash/leaseExport branch from c4bb4f5 to 44167b7 Compare March 23, 2026 23:44
@yash2710
Copy link
Copy Markdown
Contributor Author

Also, what happens if existing leases are preserved and imported leases also have the same partitions as preserved leases, which ones take precedence?

If there are existing leases, and the overwriteExisting flag is set to true, it would overwrite the preserved leases. The default value for overwriteExisting is false

makes sense, I am curious about the case when overwriteExisting is false and existing leases have the partition which importing leases also have, is there conflict resolution happening to decide which lease to take for the specific partition?

No there is no conflict resolution, it will just skip that lease

@yash2710 yash2710 force-pushed the users/trivediyash/leaseExport branch from 44167b7 to 8f42cec Compare March 26, 2026 19:49
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessor.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessor.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessor.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorBuilder.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorBuilder.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessor.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessor.cs Outdated
Copy link
Copy Markdown
Member

@kirankumarkolli kirankumarkolli left a comment

Choose a reason for hiding this comment

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

Please check my comments

Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorBuilder.cs Outdated
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
Successfully started running 1 pipeline(s).

@kirankumarkolli
Copy link
Copy Markdown
Member

@sdkReviewAgent-2

Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorCore.cs Outdated
- Make ShutdownAsync abstract in DocumentServiceLeaseStoreManager
- Add no-op override in DocumentServiceLeaseStoreManagerCosmos
- Consolidate ShutdownAsync call to single line in ChangeFeedProcessorCore

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
Successfully started running 1 pipeline(s).

@kirankumarkolli
Copy link
Copy Markdown
Member

@sdkReviewAgent

@NaluTripician
Copy link
Copy Markdown
Contributor

PR Deep Review Summary

Thanks for iterating on this — a lot of prior feedback has already been addressed (stream disposal via leaveOpen, ser/deser co-location into the in-memory manager, ShutdownAsync lifted onto DocumentServiceLeaseStoreManager, logging order in StopAsync).

Posting 7 new findings below (1 🔴 Blocking, 4 🟡 Recommendations, 2 🟢/💬). I reviewed all existing comments and skipped items that are already covered by prior reviewers.

Top concern: the runtime guard intended to reject non-resizable MemoryStream inputs (leaseState.SetLength(leaseState.Length)) is ineffective — MemoryStream.SetLength only throws when value > capacity, and for new MemoryStream(byte[]) the length equals capacity at construction. I verified this empirically on .NET 8. Consequence: the documented restore pattern (new MemoryStream(File.ReadAllBytes(...))) passes validation but fails at shutdown the moment serialized state grows, and one of the new unit tests asserts on behavior that does not occur.

Details inline.


⚠️ AI-generated review — may be incorrect. Agree? → resolve the conversation. Disagree? → reply with your reasoning.

Comment thread Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorBuilder.cs Outdated
Remove SetLength validation from WithInMemoryLeaseContainer. Non-expandable
stream errors will propagate naturally from ShutdownAsync when it tries to
write. Also reorders validation so state-check runs before stream inspection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
Successfully started running 1 pipeline(s).

@NaluTripician
Copy link
Copy Markdown
Contributor

NaluTripician commented Apr 23, 2026

Re-review after commit 40551c6

Thanks for the quick turnaround. Status of my prior findings:

Addressed — thank you:

  • 🔴 F1 (ineffective SetLength(Length) guard) — resolved by removing the eager validation entirely.
  • 🟡 F4 (WithInMemoryLeaseContainerWithNonResizableStreamThrows was a false-positive test) — removed alongside the guard.
  • 🟢 F7 (validation order) — ValidateNoLeaseContainerConfigured() now runs before the argument checks, so the user stream isn't mutated before we decide to reject the call.

Still open from the earlier round (code unchanged; my inline comments stand):

  • 🟡 F3 — DocumentServiceLeaseContainerInMemory.ShutdownAsync writes to the stream and then calls SetLength(Position); if the caller passed a stream whose buffer already contained more bytes (e.g. reused from a prior run), the trailing bytes are truncated but can also be partially overwritten in place, leaving a corrupted payload if the write throws mid-flight.
  • 🟡 F5 — ChangeFeedProcessorBuilderTests.FullLifecycle constructs the lease-store manager directly and never runs it through the processor, so the test doesn't actually exercise the lifecycle it claims to.
  • 🟢 F6 — DeserializeLeaseState silently overwrites duplicate lease IDs instead of failing fast.
  • 💬 F9 — DocumentServiceLeaseConverter mutates a shared ContractResolver on a shared JsonSerializer — racy under concurrent use.

🟡 New finding from the fix itself · Documentation: Usage Example contradicts the (now-only) guard rail

With the eager validation removed, the XML doc warning is the only defense against non-resizable streams:

"The stream must be writable and expandable (for example, created via new MemoryStream()). A fixed-size stream such as new MemoryStream(byte[]) will fail at shutdown if the serialized lease state exceeds the original buffer capacity."

But the PR description's canonical Usage Example still does the opposite:

byte[] savedState = File.ReadAllBytes("leases.json");
MemoryStream restoredState = new MemoryStream(savedState);  // <-- non-resizable

This example is the thing that gets copied into customer samples, blog posts, and StackOverflow answers. Users who follow it will:

  1. Restore from a byte array → stream is non-resizable.
  2. Start the processor → works fine (only reads during init).
  3. Acquire new leases / continuation tokens grow / owner changes → serialized state grows even a little.
  4. StopAsync throws InvalidOperationException (Memory stream is not expandable.) at shutdown — exactly the worst time, and with no prior signal.

Because the runtime guard has been removed, the documented pattern now silently succeeds until it bites in production.

Suggested fix — update the Usage Example (both in the PR description and anywhere this lands in customer-facing docs / <example> XML) to explicitly produce a resizable stream:

byte[] savedState = File.ReadAllBytes("leases.json");
MemoryStream restoredState = new MemoryStream();
restoredState.Write(savedState, 0, savedState.Length);
restoredState.Position = 0;

Or wrap as a helper and call it out in a comment: // Resizable copy — new MemoryStream(byte[]) would fail at shutdown.


Also still unresolved from @xinlian12's earlier comment: if partitionManager.StopAsync() throws inside ChangeFeedProcessorCore.StopAsync, ShutdownAsync on the lease-store manager is skipped, so the in-memory lease state never gets persisted to the caller's stream. Worth deciding whether that path should use a try/finally.


⚠️ AI-generated review — may be incorrect. Agree? → resolve the conversation. Disagree? → reply with your reasoning.

@xinlian12
Copy link
Copy Markdown
Member

Review complete (44:03)

No new comments — existing review coverage is sufficient.

Steps: ✓ context, correctness, cross-sdk, design, history, past-prs, synthesis, test-coverage

kirankumarkolli and others added 2 commits April 24, 2026 11:24
…ss and clarity

Addresses review feedback on PR #5579:

- Persists lease state before stopping partition manager so shutdown ordering is deterministic (no try/finally/rethrow needed).

- Extracts serialization into InMemoryLeaseJsonFormat helper so writer and reader cannot drift.

- Writes SetLength before Serialize so a non-resizable buffer fails fast with a descriptive exception instead of corrupting stream contents.

- Removes the unused SemaphoreSlim gate; ShutdownAsync has a single call site via ChangeFeedProcessor.StopAsync.

- Throws on duplicate lease ids during deserialization and leaves the source stream positioned at 0 on success.

- Expands XML documentation on WithInMemoryLeaseContainer and the base DocumentServiceLeaseStoreManager.ShutdownAsync.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Expands round-trip coverage to verify Properties (with unicode), FeedRange, and Timestamp survive persist/reload.

- Adds Deserialize_DuplicateIds_Throws to lock in the dup-id guard.

- Adds Deserialize_LeavesStreamPositionAtZero to pin the exit contract.

- Updates ShutdownAsync_WithDisposedStream_Throws to expect InvalidOperationException after the SetLength-first reorder.

- Removes StopAsync_AfterStop_CanRestart and StopAsync_WhenPartitionManagerThrows_StillCallsShutdownAsync; both premises are obsolete under the persist-first ordering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
Successfully started running 1 pipeline(s).

@kirankumarkolli kirankumarkolli self-assigned this Apr 24, 2026
The WithInMemoryLeaseContainer XML had a contradiction: the param guard rail warns against fixed-size MemoryStreams (new MemoryStream(byte[])), but the usage example a few lines later told callers to rehydrate by passing a new MemoryStream 'seeded with those bytes' -- exactly the non-resizable constructor the guard rail forbids.

Replace the rehydrate sentence with an expandable pattern (new MemoryStream(), Write, Position = 0) so the example is consistent with the guard rail and actually works on restore.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@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).

@yash2710 yash2710 merged commit a1958e2 into master Apr 24, 2026
33 checks passed
@yash2710 yash2710 deleted the users/trivediyash/leaseExport branch April 24, 2026 20:36
@NaluTripician NaluTripician mentioned this pull request Apr 24, 2026
4 tasks
microsoft-github-policy-service Bot pushed a commit that referenced this pull request Apr 25, 2026
## Release 3.59.0

### Version Changes
- ClientOfficialVersion: 3.58.0 → 3.59.0
- ClientPreviewVersion: 3.59.0 → 3.60.0
- ClientPreviewSuffixVersion: preview.0 → preview.0

### Changelog (3.59.0 GA)

#### Added
- [5579](#5579)
Change Feed Processor: Adds Lease container export support
- [5709](#5709)
Performance: Adds caching for URL-encoded AAD authorization signature
- [5731](#5731) DNS
dot-suffix: Adds TCP DNS dot-suffix for Direct mode to avoid Kubernetes
ndots latency
- [5755](#5755)
Exceptionless: Adds enabling exception less 400 status code
- [5756](#5756)
Exceptionless: Adds enabling exception less 404/1002 status code
- [5757](#5757)
Exceptionless: Adds enabling exception less 403
- [5779](#5779)
Direct: Adds Direct package version bump to 3.42.4
- [5786](#5786)
Region Availability: Adds missing regions from Direct 3.42.4
- [5788](#5788)
Socket Handler: Adds HTTP/2 PING keep-alive to detect broken connections
in pool

#### Fixed
- [5553](#5553)
NativeDLLs: Fixes Conditionally include win-x64 native DLLs based on
RuntimeIdentifier
- [5588](#5588)
LINQ: Fixes memory leak from Expression.Compile() in all call sites
- [5617](#5617)
ChangeFeedProcessor: Fixes first-change skip during initial startup by
anchoring StartTime
- [5636](#5636)
CosmosClientBuilder: Fixes self-referencing loop in
GetSerializedConfiguration with STJ TypeInfoResolver
- [5748](#5748)
Routing: Fixes GetOverlappingRanges CPU overhead from repeated JSON
deserialization
- [5807](#5807)
ChangeFeedProcessor: Fixes lease de-duplication for
/partitionKey-partitioned lease containers

### Changelog (3.60.0-preview.0)

#### Added
- [5804](#5804)
SemanticReranking: Adds Configurable Request Timeout

#### Fixed
- [5783](#5783)
Container: Fixes SemanticRerankAsync TypeLoadException in derived
classes

### API Contract Diff (GA)
```diff
diff --git "a/Microsoft.Azure.Cosmos\\contracts\\API_3.58.0.txt" "b/Microsoft.Azure.Cosmos\\contracts\\API_3.59.0.txt"
index 1b74a69..6fa9352 100644
--- "a/Microsoft.Azure.Cosmos\\contracts\\API_3.58.0.txt"
+++ "b/Microsoft.Azure.Cosmos\\contracts\\API_3.59.0.txt"
@@ -60,6 +60,7 @@ namespace Microsoft.Azure.Cosmos
         public ChangeFeedProcessor Build();
         public ChangeFeedProcessorBuilder WithErrorNotification(Container.ChangeFeedMonitorErrorDelegate errorDelegate);
         public virtual ChangeFeedProcessorBuilder WithInMemoryLeaseContainer();
+        public virtual ChangeFeedProcessorBuilder WithInMemoryLeaseContainer(MemoryStream leaseState);
         public ChangeFeedProcessorBuilder WithInstanceName(string instanceName);
         public ChangeFeedProcessorBuilder WithLeaseAcquireNotification(Container.ChangeFeedMonitorLeaseAcquireDelegate acquireDelegate);
         public ChangeFeedProcessorBuilder WithLeaseConfiguration(Nullable<TimeSpan> acquireInterval=default(Nullable<TimeSpan>), Nullable<TimeSpan> expirationInterval=default(Nullable<TimeSpan>), Nullable<TimeSpan> renewInterval=default(Nullable<TimeSpan>));
@@ -956,6 +957,7 @@ namespace Microsoft.Azure.Cosmos
         public const string NorwayWest = "Norway West";
         public const string PolandCentral = "Poland Central";
         public const string QatarCentral = "Qatar Central";
+        public const string SaudiArabiaEast = "Saudi Arabia East";
         public const string SingaporeCentral = "Singapore Central";
         public const string SingaporeNorth = "Singapore North";
         public const string SouthAfricaNorth = "South Africa North";
@@ -963,6 +965,7 @@ namespace Microsoft.Azure.Cosmos
         public const string SouthCentralUS = "South Central US";
         public const string SouthCentralUS2 = "South Central US 2";
         public const string SoutheastAsia = "Southeast Asia";
+        public const string SoutheastAsia3 = "Southeast Asia 3";
         public const string SoutheastUS = "Southeast US";
         public const string SoutheastUS3 = "Southeast US 3";
         public const string SoutheastUS5 = "Southeast US 5";
@@ -990,6 +993,7 @@ namespace Microsoft.Azure.Cosmos
         public const string USSecWest = "USSec West";
         public const string USSecWestCentral = "USSec West Central";
         public const string WestCentralUS = "West Central US";
+        public const string WestCentralUSFRE = "West Central US FRE";
         public const string WestEurope = "West Europe";
         public const string WestIndia = "West India";
         public const string WestUS = "West US";

```

### API Contract Diff (Preview)
```diff
diff --git "a/Microsoft.Azure.Cosmos\\contracts\\API_3.59.0-preview.0.txt" "b/Microsoft.Azure.Cosmos\\contracts\\API_3.60.0-preview.0.txt"
index 1ae52c0..58df10f 100644
--- "a/Microsoft.Azure.Cosmos\\contracts\\API_3.59.0-preview.0.txt"
+++ "b/Microsoft.Azure.Cosmos\\contracts\\API_3.60.0-preview.0.txt"
@@ -91,6 +91,7 @@ namespace Microsoft.Azure.Cosmos
         public ChangeFeedProcessor Build();
         public ChangeFeedProcessorBuilder WithErrorNotification(Container.ChangeFeedMonitorErrorDelegate errorDelegate);
         public virtual ChangeFeedProcessorBuilder WithInMemoryLeaseContainer();
+        public virtual ChangeFeedProcessorBuilder WithInMemoryLeaseContainer(MemoryStream leaseState);
         public ChangeFeedProcessorBuilder WithInstanceName(string instanceName);
         public ChangeFeedProcessorBuilder WithLeaseAcquireNotification(Container.ChangeFeedMonitorLeaseAcquireDelegate acquireDelegate);
         public ChangeFeedProcessorBuilder WithLeaseConfiguration(Nullable<TimeSpan> acquireInterval=default(Nullable<TimeSpan>), Nullable<TimeSpan> expirationInterval=default(Nullable<TimeSpan>), Nullable<TimeSpan> renewInterval=default(Nullable<TimeSpan>));
@@ -302,7 +303,7 @@ namespace Microsoft.Azure.Cosmos
         public abstract Task<ResponseMessage> ReplaceItemStreamAsync(Stream streamPayload, string id, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken));
         public abstract Task<ThroughputResponse> ReplaceThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken));
         public abstract Task<ThroughputResponse> ReplaceThroughputAsync(int throughput, RequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken));
-        public abstract Task<SemanticRerankResult> SemanticRerankAsync(string rerankContext, IEnumerable<string> documents, IDictionary<string, object> options=null, CancellationToken cancellationToken=default(CancellationToken));
+        public virtual Task<SemanticRerankResult> SemanticRerankAsync(string rerankContext, IEnumerable<string> documents, IDictionary<string, object> options=null, CancellationToken cancellationToken=default(CancellationToken));
         public abstract Task<ItemResponse<T>> UpsertItemAsync<T>(T item, Nullable<PartitionKey> partitionKey=default(Nullable<PartitionKey>), ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken));
         public abstract Task<ResponseMessage> UpsertItemStreamAsync(Stream streamPayload, PartitionKey partitionKey, ItemRequestOptions requestOptions=null, CancellationToken cancellationToken=default(CancellationToken));
         public delegate Task ChangeFeedHandlerWithManualCheckpoint<T>(ChangeFeedProcessorContext context, IReadOnlyCollection<T> changes, Func<Task> checkpointAsync, CancellationToken cancellationToken);
@@ -407,6 +408,7 @@ namespace Microsoft.Azure.Cosmos
         public int GatewayModeMaxConnectionLimit { get; set; }
         public Func<HttpClient> HttpClientFactory { get; set; }
         public Nullable<TimeSpan> IdleTcpConnectionTimeout { get; set; }
+        public TimeSpan InferenceRequestTimeout { get; set; }
         public bool LimitToEndpoint { get; set; }
         public Nullable<int> MaxRequestsPerTcpConnection { get; set; }
         public Nullable<int> MaxRetryAttemptsOnRateLimitedRequests { get; set; }
@@ -1092,6 +1094,7 @@ namespace Microsoft.Azure.Cosmos
         public const string NorwayWest = "Norway West";
         public const string PolandCentral = "Poland Central";
         public const string QatarCentral = "Qatar Central";
+        public const string SaudiArabiaEast = "Saudi Arabia East";
         public const string SingaporeCentral = "Singapore Central";
         public const string SingaporeNorth = "Singapore North";
         public const string SouthAfricaNorth = "South Africa North";
@@ -1099,6 +1102,7 @@ namespace Microsoft.Azure.Cosmos
         public const string SouthCentralUS = "South Central US";
         public const string SouthCentralUS2 = "South Central US 2";
         public const string SoutheastAsia = "Southeast Asia";
+        public const string SoutheastAsia3 = "Southeast Asia 3";
         public const string SoutheastUS = "Southeast US";
         public const string SoutheastUS3 = "Southeast US 3";
         public const string SoutheastUS5 = "Southeast US 5";
@@ -1126,6 +1130,7 @@ namespace Microsoft.Azure.Cosmos
         public const string USSecWest = "USSec West";
         public const string USSecWestCentral = "USSec West Central";
         public const string WestCentralUS = "West Central US";
+        public const string WestCentralUSFRE = "West Central US FRE";
         public const string WestEurope = "West Europe";
         public const string WestIndia = "West India";
         public const string WestUS = "West US";
@@ -1504,6 +1509,7 @@ namespace Microsoft.Azure.Cosmos.Fluent
         public CosmosClientBuilder WithEnableRemoteRegionPreferredForSessionRetry(bool enableRemoteRegionPreferredForSessionRetry);
         public CosmosClientBuilder WithFaultInjection(IFaultInjector faultInjector);
         public CosmosClientBuilder WithHttpClientFactory(Func<HttpClient> httpClientFactory);
+        public CosmosClientBuilder WithInferenceRequestTimeout(TimeSpan inferenceRequestTimeout);
         public CosmosClientBuilder WithLimitToEndpoint(bool limitToEndpoint);
         public CosmosClientBuilder WithPriorityLevel(PriorityLevel priorityLevel);
         public CosmosClientBuilder WithReadConsistencyStrategy(ReadConsistencyStrategy readConsistencyStrategy);

```

### Checklist
- [ ] Changelog entries reviewed by team
- [ ] API contract diff reviewed by Kiran and Kirill
- [ ] Preview APIs reviewed (email sent to
azurecosmossdkdotnet@microsoft.com)
- [ ] Kiran sign-off obtained

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

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Lease Import/Export for Change Feed Processor

6 participants