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));
        }
예제 #3
0
        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);
        }
예제 #4
0
        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");
        }