Change Feed Processor: Adds Lease container export support#5579
Change Feed Processor: Adds Lease container export support#5579
Conversation
dce1b84 to
f6b9083
Compare
|
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? |
If there are existing leases, and the |
makes sense, I am curious about the case when |
9f631f1 to
cc61cc3
Compare
c4bb4f5 to
44167b7
Compare
No there is no conflict resolution, it will just skip that lease |
44167b7 to
8f42cec
Compare
kirankumarkolli
left a comment
There was a problem hiding this comment.
Please check my comments
Description
This PR adds the ability to persist and restore in-memory ChangeFeed processor lease state via a
MemoryStream. When a processor is built withWithInMemoryLeaseContainer(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
Design Decisions
Single MemoryStream for Read and Write
MemoryStreamserves dual purpose: if it contains data on init, leases are deserialized from it. OnStopAsync, current lease state is serialized back into the same stream.Persist-First Shutdown Ordering
ChangeFeedProcessorCore.StopAsynccallsstoreManager.ShutdownAsync()beforepartitionManager.StopAsync().Stream Writer Correctness
DocumentServiceLeaseContainerInMemory.ShutdownAsynccallsSetLength(serializedBytes.Length)before writing. If the supplied stream is not expandable and cannot hold the new payload,SetLengththrows and the user's stream is left untouched — no partial-write corruption.InvalidOperationExceptionwith a message pointing callers atnew MemoryStream()instead ofnew MemoryStream(byte[]).Automatic Persistence on Stop
StopAsyncflow, via a virtualShutdownAsync()lifecycle hook on the internalDocumentServiceLeaseContainerbase class, overridden only by the in-memory implementation.Shared Serialization Format
InMemoryLeaseJsonFormat, a single internal helper that owns encoding, buffer size, andJsonSerializersettings. This prevents silent drift between writer and reader.Duplicate Lease Detection
DocumentServiceLeaseStoreManagerInMemory.DeserializeLeaseStatefails fast withInvalidOperationExceptionif the persisted state contains duplicate lease ids, rather than silently overwriting entries.No Changes to Cosmos-Backed Leases
ShutdownAsyncbase class method is a no-op for implementations that manage their own persistence.In-Memory Only
Usage Example
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 asInvalidOperationException.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 asInvalidOperationException.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 preservesLeaseToken,ContinuationToken,Owner,Properties(including unicode),FeedRange, andTimestamp.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— VerifiesShutdownAsyncis 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
Closing issues
closes #5580