public static ChangeFeedPartitionKeyResultSetIteratorCore Create( DocumentServiceLease lease, string continuationToken, int?maxItemCount, ContainerInternal container, DateTime?startTime, bool startFromBeginning) { // If the lease represents a full partition (old schema) then use a FeedRangePartitionKeyRange // If the lease represents an EPK range (new schema) the use the FeedRange in the lease FeedRangeInternal feedRange = lease is DocumentServiceLeaseCoreEpk ? lease.FeedRange : new FeedRangePartitionKeyRange(lease.CurrentLeaseToken); ChangeFeedStartFrom startFrom; if (continuationToken != null) { // For continuation based feed range we need to manufactor a new continuation token that has the partition key range id in it. startFrom = new ChangeFeedStartFromContinuationAndFeedRange(continuationToken, feedRange); } else if (startTime.HasValue) { startFrom = ChangeFeedStartFrom.Time(startTime.Value, feedRange); } else if (startFromBeginning) { startFrom = ChangeFeedStartFrom.Beginning(feedRange); } else { startFrom = ChangeFeedStartFrom.Now(feedRange); } ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions() { PageSizeHint = maxItemCount, }; return(new ChangeFeedPartitionKeyResultSetIteratorCore( container: container, changeFeedStartFrom: startFrom, options: requestOptions)); }
public static ChangeFeedPartitionKeyResultSetIteratorCore BuildResultSetIterator( string partitionKeyRangeId, string continuationToken, int?maxItemCount, ContainerInternal container, DateTime?startTime, bool startFromBeginning) { FeedRangeInternal feedRange = new FeedRangePartitionKeyRange(partitionKeyRangeId); ChangeFeedStartFrom startFrom; if (continuationToken != null) { // For continuation based feed range we need to manufactor a new continuation token that has the partition key range id in it. startFrom = new ChangeFeedStartFromContinuationAndFeedRange(continuationToken, feedRange); } else if (startTime.HasValue) { startFrom = ChangeFeedStartFrom.Time(startTime.Value, feedRange); } else if (startFromBeginning) { startFrom = ChangeFeedStartFrom.Beginning(feedRange); } else { startFrom = ChangeFeedStartFrom.Now(feedRange); } ChangeFeedRequestOptions requestOptions = new ChangeFeedRequestOptions() { PageSizeHint = maxItemCount, }; return(new ChangeFeedPartitionKeyResultSetIteratorCore( clientContext: container.ClientContext, container: container, changeFeedStartFrom: startFrom, options: requestOptions)); }
public async Task StartFromNowAsync(bool useContinuations) { int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate( documentContainer, new ChangeFeedRequestOptions(), ChangeFeedStartFrom.Now(), cancellationToken: default); Assert.IsTrue(monadicEnumerator.Succeeded); CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result; Assert.AreEqual(0, await(useContinuations ? DrainWithUntilNotModifiedWithContinuationTokens(documentContainer, enumerator) : DrainUntilNotModifedAsync(enumerator))); for (int i = 0; i < numItems; i++) { // Insert an item CosmosObject item = CosmosObject.Parse($"{{\"pk\" : {i} }}"); while (true) { TryCatch <Record> monadicCreateRecord = await documentContainer.MonadicCreateItemAsync(item, cancellationToken : default); if (monadicCreateRecord.Succeeded) { break; } } } int globalCount = await(useContinuations ? DrainWithUntilNotModifiedWithContinuationTokens(documentContainer, enumerator) : DrainUntilNotModifedAsync(enumerator)); Assert.AreEqual(numItems, globalCount); }
public async Task ChangeFeedIteratorCore_WithFullFidelity() { ContainerProperties properties = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: ChangeFeedIteratorCoreTests.PartitionKey); properties.ChangeFeedPolicy.FullFidelityRetention = TimeSpan.FromMinutes(5); ContainerResponse response = await this.database.CreateContainerAsync( properties, cancellationToken : this.cancellationToken); ContainerInternal container = (ContainerInternal)response; // FF does not work with StartFromBeginning currently, so we capture an initial continuation. FeedIterator <ToDoActivityWithMetadata> fullFidelityIterator = container.GetChangeFeedIterator <ToDoActivityWithMetadata>( ChangeFeedStartFrom.Now(), ChangeFeedMode.FullFidelity); string initialContinuation = null; while (fullFidelityIterator.HasMoreResults) { try { FeedResponse <ToDoActivityWithMetadata> feedResponse = await fullFidelityIterator.ReadNextAsync(this.cancellationToken); initialContinuation = feedResponse.ContinuationToken; } catch (CosmosException cosmosException) when(cosmosException.StatusCode == HttpStatusCode.NotModified) { initialContinuation = cosmosException.Headers.ContinuationToken; break; } } // Insert documents and then delete them int totalDocuments = 50; IList <ToDoActivity> createdItems = await this.CreateRandomItems(container, totalDocuments, randomPartitionKey : true); foreach (ToDoActivity item in createdItems) { await container.DeleteItemAsync <ToDoActivity>(item.id, new PartitionKey(item.pk)); } // Resume Change Feed and verify we pickup all the events fullFidelityIterator = container.GetChangeFeedIterator <ToDoActivityWithMetadata>( ChangeFeedStartFrom.ContinuationToken(initialContinuation), ChangeFeedMode.FullFidelity); int detectedEvents = 0; bool hasInserts = false; bool hasDeletes = false; while (fullFidelityIterator.HasMoreResults) { try { FeedResponse <ToDoActivityWithMetadata> feedResponse = await fullFidelityIterator.ReadNextAsync(this.cancellationToken); foreach (ToDoActivityWithMetadata item in feedResponse) { Assert.IsNotNull(item.metadata, "Metadata not present"); Assert.IsNotNull(item.metadata.operationType, "Metadata has no operationType"); hasInserts |= item.metadata.operationType == "create"; hasDeletes |= item.metadata.operationType == "delete"; } detectedEvents += feedResponse.Count; } catch (CosmosException cosmosException) when(cosmosException.StatusCode == HttpStatusCode.NotModified) { break; } } Assert.AreEqual(2 * totalDocuments, detectedEvents, "Full Fidelity should include inserts and delete events."); Assert.IsTrue(hasInserts, "No metadata for create operationType found"); Assert.IsTrue(hasDeletes, "No metadata for delete operationType found"); }