Esempio n. 1
0
            internal static TryCatch <ChangeFeedCrossFeedRangeState> CreateFromCosmosElement(CosmosElement cosmosElement)
            {
                if (cosmosElement == null)
                {
                    throw new ArgumentNullException(nameof(cosmosElement));
                }

                if (!(cosmosElement is CosmosArray cosmosArray))
                {
                    return(TryCatch <ChangeFeedCrossFeedRangeState> .FromException(
                               new FormatException(
                                   $"Expected array: {cosmosElement}")));
                }

                List <FeedRangeState <ChangeFeedState> > changeFeedFeedRangeStates = new List <FeedRangeState <ChangeFeedState> >(capacity: cosmosArray.Count);

                foreach (CosmosElement arrayItem in cosmosArray)
                {
                    TryCatch <FeedRangeState <ChangeFeedState> > monadicChangeFeedFeedRangeState = ChangeFeedFeedRangeStateSerializer.Monadic.CreateFromCosmosElement(arrayItem);
                    if (monadicChangeFeedFeedRangeState.Failed)
                    {
                        return(TryCatch <ChangeFeedCrossFeedRangeState> .FromException(monadicChangeFeedFeedRangeState.Exception));
                    }

                    changeFeedFeedRangeStates.Add(monadicChangeFeedFeedRangeState.Result);
                }

                ImmutableArray <FeedRangeState <ChangeFeedState> > feedRangeStates = changeFeedFeedRangeStates.ToImmutableArray();
                ChangeFeedCrossFeedRangeState changeFeedCrossFeedRangeState        = new ChangeFeedCrossFeedRangeState(feedRangeStates);

                return(TryCatch <ChangeFeedCrossFeedRangeState> .FromResult(changeFeedCrossFeedRangeState));
            }
        public async Task SerializeAndDeserializeContinuationToken()
        {
            int batchSize = 25;

            (int totalCount, ChangeFeedCrossFeedRangeState state)countAndState;
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromBeginning(),
                ChangeFeedMode.Incremental);

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            countAndState = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);

            // Serialize the state and send it over the wire for your user to resume execution.
            string continuationToken = countAndState.state.ToString();

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            // Deserialize the state that the user came back with to resume from.
            ChangeFeedCrossFeedRangeState state = ChangeFeedCrossFeedRangeState.Parse(continuationToken);

            asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(state, ChangeFeedMode.Incremental);
            countAndState   = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);
        }
 public static ChangeFeedPage CreateNotModifiedPage(
     double requestCharge,
     string activityId,
     ChangeFeedCrossFeedRangeState state,
     ImmutableDictionary <string, string> additionalHeaders)
 {
     return(new ChangeFeedPage(CosmosArray.Empty, notModified: true, requestCharge, activityId, state, additionalHeaders));
 }
Esempio n. 4
0
        public ChangeFeedCrossFeedRangeState Merge(ChangeFeedCrossFeedRangeState first)
        {
            Memory <FeedRangeState <ChangeFeedState> > mergedRange = CrossFeedRangeStateSplitterAndMerger.Merge <ChangeFeedState>(
                this.FeedRangeStates,
                first.FeedRangeStates);

            return(new ChangeFeedCrossFeedRangeState(mergedRange));
        }
 public ChangeFeedCrossFeedRangeAsyncEnumerable(
     IDocumentContainer documentContainer,
     ChangeFeedRequestOptions changeFeedRequestOptions,
     ChangeFeedCrossFeedRangeState state)
 {
     this.documentContainer        = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer));
     this.changeFeedRequestOptions = changeFeedRequestOptions;
     this.state = state;
 }
 public static ChangeFeedPage CreatePageWithChanges(
     CosmosArray documents,
     double requestCharge,
     string activityId,
     ChangeFeedCrossFeedRangeState state,
     ImmutableDictionary <string, string> additionalHeaders)
 {
     return(new ChangeFeedPage(documents, notModified: false, requestCharge, activityId, state, additionalHeaders));
 }
 public ChangeFeedCrossFeedRangeAsyncEnumerable(
     IDocumentContainer documentContainer,
     ChangeFeedCrossFeedRangeState state,
     ChangeFeedPaginationOptions changeFeedPaginationOptions,
     JsonSerializationFormatOptions jsonSerializationFormatOptions = null)
 {
     this.documentContainer           = documentContainer ?? throw new ArgumentNullException(nameof(documentContainer));
     this.changeFeedPaginationOptions = changeFeedPaginationOptions ?? ChangeFeedPaginationOptions.Default;
     this.state = state;
     this.jsonSerializationFormatOptions = jsonSerializationFormatOptions;
 }
Esempio n. 8
0
 private ChangeFeedPage(
     CosmosArray documents,
     bool notModified,
     double requestCharge,
     string activityId,
     ChangeFeedCrossFeedRangeState state)
 {
     this.Documents     = documents ?? throw new ArgumentOutOfRangeException(nameof(documents));
     this.NotModified   = notModified;
     this.RequestCharge = requestCharge < 0 ? throw new ArgumentOutOfRangeException(nameof(requestCharge)) : requestCharge;
     this.ActivityId    = activityId ?? throw new ArgumentNullException(nameof(activityId));
     this.State         = state;
 }
Esempio n. 9
0
        public async Task TestCancellationToken()
        {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

            cancellationTokenSource.Cancel();

            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromBeginning());

            await foreach (TryCatch <ChangeFeedPage> monadicPage in asyncEnumerable.WithCancellation(cancellationTokenSource.Token))
            {
                monadicPage.ThrowIfFailed();
            }
        }
        public async Task TargetMultipleLogicalPartitionKeys()
        {
            int batchSize = 25;

            string pkToRead1 = "pkToRead1";
            string pkToRead2 = "pkToRead2";
            string otherPK   = "otherPK";

            for (int i = 0; i < batchSize; i++)
            {
                await this.Container.CreateItemAsync(this.CreateRandomToDoActivity(pkToRead1));
            }

            for (int i = 0; i < batchSize; i++)
            {
                await this.Container.CreateItemAsync(this.CreateRandomToDoActivity(pkToRead2));
            }

            for (int i = 0; i < batchSize; i++)
            {
                await this.Container.CreateItemAsync(this.CreateRandomToDoActivity(otherPK));
            }

            // Create one start state for each logical partition key.
            List <FeedRangeState <ChangeFeedState> > feedRangeStates = new List <FeedRangeState <ChangeFeedState> >();
            IReadOnlyList <string> partitionKeysToTarget             = new List <string>()
            {
                pkToRead1,
                pkToRead2
            };

            foreach (string partitionKeyToTarget in partitionKeysToTarget)
            {
                feedRangeStates.Add(
                    new FeedRangeState <ChangeFeedState>(
                        (FeedRangeInternal)FeedRange.FromPartitionKey(
                            new Cosmos.PartitionKey(partitionKeyToTarget)),
                        ChangeFeedState.Beginning()));
            }

            // Use the list composition property of the constructor to merge them in to a single state.
            ChangeFeedCrossFeedRangeState multipleLogicalPartitionKeyState = new ChangeFeedCrossFeedRangeState(feedRangeStates.ToImmutableArray());
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable  = this.Container.GetChangeFeedAsyncEnumerable(multipleLogicalPartitionKeyState, ChangeFeedMode.Incremental);

            (int totalCount, ChangeFeedCrossFeedRangeState _) = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(2 * batchSize, totalCount);
        }
Esempio n. 11
0
        public bool TrySplit(out ChangeFeedCrossFeedRangeState first, out ChangeFeedCrossFeedRangeState second)
        {
            if (!CrossFeedRangeStateSplitterAndMerger.TrySplit(
                    this.FeedRangeStates,
                    out ReadOnlyMemory <FeedRangeState <ChangeFeedState> > firstRange,
                    out ReadOnlyMemory <FeedRangeState <ChangeFeedState> > secondRange))
            {
                first  = default;
                second = default;
                return(false);
            }

            first  = new ChangeFeedCrossFeedRangeState(firstRange);
            second = new ChangeFeedCrossFeedRangeState(secondRange);
            return(true);
        }
Esempio n. 12
0
        public static bool TryParse(string text, out ChangeFeedCrossFeedRangeState state)
        {
            if (text == null)
            {
                throw new ArgumentNullException(nameof(text));
            }

            TryCatch <ChangeFeedCrossFeedRangeState> monadicParse = Monadic.Parse(text);

            if (monadicParse.Failed)
            {
                state = default;
                return(false);
            }

            state = monadicParse.Result;
            return(true);
        }
        public async Task TestContentSerializationOptions()
        {
            {
                // Native format
                IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                    ChangeFeedCrossFeedRangeState.CreateFromBeginning(),
                    ChangeFeedMode.Incremental,
                    new ChangeFeedRequestOptions()
                {
                    JsonSerializationFormatOptions = JsonSerializationFormatOptions.Create(JsonSerializationFormat.Binary)
                });
                await foreach (TryCatch <ChangeFeedPage> monadicPage in asyncEnumerable)
                {
                    monadicPage.ThrowIfFailed();

                    if (monadicPage.Result.NotModified)
                    {
                        break;
                    }
                }
            }

            {
                // Custom format
                IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                    ChangeFeedCrossFeedRangeState.CreateFromBeginning(),
                    ChangeFeedMode.Incremental,
                    new ChangeFeedRequestOptions()
                {
                    JsonSerializationFormatOptions = JsonSerializationFormatOptions.Create(
                        JsonSerializationFormat.Binary,
                        (content) => JsonNavigator.Create(content))
                });
                await foreach (TryCatch <ChangeFeedPage> monadicPage in asyncEnumerable)
                {
                    monadicPage.ThrowIfFailed();

                    if (monadicPage.Result.NotModified)
                    {
                        break;
                    }
                }
            }
        }
        public async Task TestScaleUpAndScaleDown()
        {
            int batchSize = 25;

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            // Start draining as 1 iterator
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromBeginning(),
                ChangeFeedMode.Incremental);

            (int totalCount, ChangeFeedCrossFeedRangeState state) = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, totalCount);

            // Continue draining as two iterators
            if (!state.TrySplit(out ChangeFeedCrossFeedRangeState first, out ChangeFeedCrossFeedRangeState second))
            {
                Assert.Fail("Failed to split");
            }

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            IAsyncEnumerable <TryCatch <ChangeFeedPage> > leftEnumerable = this.Container.GetChangeFeedAsyncEnumerable(first, ChangeFeedMode.Incremental);

            (int leftTotalCount, ChangeFeedCrossFeedRangeState leftResumeState) = await PartialDrainAsync(leftEnumerable);

            IAsyncEnumerable <TryCatch <ChangeFeedPage> > rightEnumerable = this.Container.GetChangeFeedAsyncEnumerable(second, ChangeFeedMode.Incremental);

            (int rightTotalCount, ChangeFeedCrossFeedRangeState rightResumeState) = await PartialDrainAsync(rightEnumerable);

            Assert.AreEqual(batchSize, leftTotalCount + rightTotalCount);

            // Finish draining again as a single enumerator
            ChangeFeedCrossFeedRangeState mergedState = leftResumeState.Merge(rightResumeState);

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            IAsyncEnumerable <TryCatch <ChangeFeedPage> > mergedEnumerable = this.Container.GetChangeFeedAsyncEnumerable(mergedState, ChangeFeedMode.Incremental);

            (int mergedTotalCount, ChangeFeedCrossFeedRangeState _) = await PartialDrainAsync(mergedEnumerable);

            Assert.AreEqual(batchSize, mergedTotalCount);
        }
Esempio n. 15
0
        public async Task TestCustomRequestOptionsAsync()
        {
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromBeginning(),
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions()
            {
                Properties = new Dictionary <string, object>()
                {
                    { HttpConstants.HttpHeaders.SessionToken, "AnInvalidSessionToken" }
                }
            });

            await foreach (TryCatch <ChangeFeedPage> monadicPage in asyncEnumerable)
            {
                Assert.IsTrue(monadicPage.Failed);
                Assert.AreEqual(((CosmosException)monadicPage.InnerMostException).StatusCode, System.Net.HttpStatusCode.BadRequest);
                break;
            }
        }
        public async ValueTask <bool> MoveNextAsync()
        {
            if (!await this.enumerator.MoveNextAsync())
            {
                throw new InvalidOperationException("Change Feed should always be able to move next.");
            }

            TryCatch <CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> > monadicInnerChangeFeedPage = this.enumerator.Current;

            if (monadicInnerChangeFeedPage.Failed)
            {
                this.Current = TryCatch <ChangeFeedPage> .FromException(monadicInnerChangeFeedPage.Exception);

                return(true);
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> innerChangeFeedPage = monadicInnerChangeFeedPage.Result;
            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState = innerChangeFeedPage.State;
            ChangeFeedCrossFeedRangeState         state = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
            ChangeFeedPage page = innerChangeFeedPage.Page switch
            {
                Pagination.ChangeFeedSuccessPage successPage => ChangeFeedPage.CreatePageWithChanges(
                    RestFeedResponseParser.ParseRestFeedResponse(
                        successPage.Content,
                        this.jsonSerializationFormatOptions),
                    successPage.RequestCharge,
                    successPage.ActivityId,
                    state,
                    successPage.AdditionalHeaders),
                Pagination.ChangeFeedNotModifiedPage notModifiedPage => ChangeFeedPage.CreateNotModifiedPage(
                    notModifiedPage.RequestCharge,
                    notModifiedPage.ActivityId,
                    state,
                    notModifiedPage.AdditionalHeaders),
                _ => throw new InvalidOperationException($"Unknown type: {innerChangeFeedPage.Page.GetType()}"),
            };

            this.Current = TryCatch <ChangeFeedPage> .FromResult(page);

            return(true);
        }
Esempio n. 17
0
        public async Task StartFromTime()
        {
            int batchSize = 25;

            (int totalCount, ChangeFeedCrossFeedRangeState state)countAndState;
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromTime(DateTime.UtcNow.Subtract(TimeSpan.FromSeconds(1))));

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            countAndState = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(countAndState.state);
            countAndState   = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);
        }
        private static async Task <(int, ChangeFeedCrossFeedRangeState)> PartialDrainAsync(IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable)
        {
            ChangeFeedCrossFeedRangeState state = default;
            int totalCount = 0;

            await foreach (TryCatch <ChangeFeedPage> monadicPage in asyncEnumerable)
            {
                monadicPage.ThrowIfFailed();

                ChangeFeedPage page = monadicPage.Result;
                state = page.State;
                if (page.NotModified)
                {
                    break;
                }

                totalCount += page.Documents.Count;
            }

            return(totalCount, state);
        }
Esempio n. 19
0
        public async ValueTask <bool> MoveNextAsync()
        {
            if (!await this.enumerator.MoveNextAsync())
            {
                throw new InvalidOperationException("Change Feed should always be able to move next.");
            }

            TryCatch <CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> > monadicInnerChangeFeedPage = this.enumerator.Current;

            if (monadicInnerChangeFeedPage.Failed)
            {
                this.Current = TryCatch <ChangeFeedPage> .FromException(monadicInnerChangeFeedPage.Exception);

                return(true);
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> innerChangeFeedPage = monadicInnerChangeFeedPage.Result;
            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState = innerChangeFeedPage.State;
            ChangeFeedCrossFeedRangeState         state = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
            ChangeFeedPage page = innerChangeFeedPage.Page switch
            {
                Pagination.ChangeFeedSuccessPage successPage => ChangeFeedPage.CreatePageWithChanges(
                    CosmosQueryClientCore.ParseElementsFromRestStream(
                        successPage.Content,
                        Documents.ResourceType.Document,
                        cosmosSerializationOptions: null),
                    successPage.RequestCharge,
                    successPage.ActivityId,
                    state),
                Pagination.ChangeFeedNotModifiedPage notModifiedPage => ChangeFeedPage.CreateNotModifiedPage(
                    notModifiedPage.RequestCharge,
                    notModifiedPage.ActivityId,
                    state),
                _ => throw new InvalidOperationException($"Unknown type: {innerChangeFeedPage.Page.GetType()}"),
            };

            this.Current = TryCatch <ChangeFeedPage> .FromResult(page);

            return(true);
        }
Esempio n. 20
0
        public async Task StartFromBeginning()
        {
            int batchSize = 25;

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            (int totalCount, ChangeFeedCrossFeedRangeState state)countAndState;
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromBeginning());

            countAndState = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);

            // Insert another batch of 25 and use the state from the first cycle
            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(countAndState.state);
            countAndState   = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);
        }
        public async Task StartFromNow()
        {
            int batchSize = 25;

            (int totalCount, ChangeFeedCrossFeedRangeState state)countAndState;
            IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(
                ChangeFeedCrossFeedRangeState.CreateFromNow(),
                ChangeFeedMode.Incremental);

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            countAndState = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(0, countAndState.totalCount);

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(countAndState.state, ChangeFeedMode.Incremental);
            countAndState   = await PartialDrainAsync(asyncEnumerable);

            Assert.AreEqual(batchSize, countAndState.totalCount);
        }
        public async Task ParallelizeAcrossFeedRanges()
        {
            int batchSize = 25;

            await this.CreateRandomItems(this.Container, batchSize, randomPartitionKey : true);

            // Create one start state for each physical partition.
            List <ChangeFeedCrossFeedRangeState> startStates = new List <ChangeFeedCrossFeedRangeState>();
            IReadOnlyList <FeedRange>            feedRanges  = await this.Container.GetFeedRangesAsync();

            foreach (FeedRange feedRange in feedRanges)
            {
                startStates.Add(ChangeFeedCrossFeedRangeState.CreateFromBeginning(feedRange));
            }

            // Create an independant enumerable for each of those start states.
            List <IAsyncEnumerable <TryCatch <ChangeFeedPage> > > asyncEnumerables = new List <IAsyncEnumerable <TryCatch <ChangeFeedPage> > >();

            foreach (ChangeFeedCrossFeedRangeState state in startStates)
            {
                IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable = this.Container.GetChangeFeedAsyncEnumerable(state, ChangeFeedMode.Incremental);
                asyncEnumerables.Add(asyncEnumerable);
            }

            int totalCount = 0;

            foreach (IAsyncEnumerable <TryCatch <ChangeFeedPage> > asyncEnumerable in asyncEnumerables)
            {
                // This part can be done in parallel on the same machine or on different machines,
                // since they are independant enumerables.
                (int totalCount, ChangeFeedCrossFeedRangeState state)countAndState = await PartialDrainAsync(asyncEnumerable);

                totalCount += countAndState.totalCount;
            }

            Assert.AreEqual(batchSize, totalCount);
        }
        private async Task <ResponseMessage> ReadNextInternalAsync(ITrace trace, CancellationToken cancellationToken = default)
        {
            if (trace == null)
            {
                throw new ArgumentNullException(nameof(trace));
            }

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = await this.lazyMonadicEnumerator.GetValueAsync(trace, cancellationToken);

            if (monadicEnumerator.Failed)
            {
                Exception createException = monadicEnumerator.Exception;
                if (!ExceptionToCosmosException.TryCreateFromException(
                        createException,
                        trace,
                        out CosmosException cosmosException))
                {
                    // Initialization issue, there are no enumerators to invoke
                    this.hasMoreResults = false;
                    throw createException;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            enumerator.SetCancellationToken(cancellationToken);

            try
            {
                if (!await enumerator.MoveNextAsync(trace))
                {
                    throw new InvalidOperationException("ChangeFeed enumerator should always have a next continuation");
                }
            }
            catch (OperationCanceledException ex) when(!(ex is CosmosOperationCanceledException))
            {
                throw new CosmosOperationCanceledException(ex, trace);
            }

            if (enumerator.Current.Failed)
            {
                if (!ExceptionToCosmosException.TryCreateFromException(
                        enumerator.Current.Exception,
                        trace,
                        out CosmosException cosmosException))
                {
                    throw ExceptionWithStackTraceException.UnWrapMonadExcepion(enumerator.Current.Exception, trace);
                }

                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> crossFeedRangePage = enumerator.Current.Result;

            Pagination.ChangeFeedPage changeFeedPage = crossFeedRangePage.Page;
            ResponseMessage           responseMessage;

            if (changeFeedPage is Pagination.ChangeFeedSuccessPage changeFeedSuccessPage)
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.OK)
                {
                    Content = changeFeedSuccessPage.Content
                };
            }
            else
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.NotModified);
            }

            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState           = crossFeedRangePage.State;
            ChangeFeedCrossFeedRangeState         changeFeedCrossFeedRangeState = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
            string continuationToken = VersionedAndRidCheckedCompositeToken.ToCosmosElement(
                new VersionedAndRidCheckedCompositeToken(
                    VersionedAndRidCheckedCompositeToken.Version.V2,
                    changeFeedCrossFeedRangeState.ToCosmosElement(),
                    await this.documentContainer.GetResourceIdentifierAsync(trace, cancellationToken))).ToString();

            responseMessage.Headers.ContinuationToken = continuationToken;
            responseMessage.Headers.RequestCharge     = changeFeedPage.RequestCharge;
            responseMessage.Headers.ActivityId        = changeFeedPage.ActivityId;
            responseMessage.Trace = trace;

            return(responseMessage);
        }
Esempio n. 24
0
        public override async Task <ResponseMessage> ReadNextAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = await this.lazyMonadicEnumerator.GetValueAsync(cancellationToken);

            if (monadicEnumerator.Failed)
            {
                Exception       createException = monadicEnumerator.Exception;
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(createException);
                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           diagnostics: new CosmosDiagnosticsContextCore()));
            }

            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            if (!await enumerator.MoveNextAsync())
            {
                throw new InvalidOperationException("ChangeFeed enumerator should always have a next continuation");
            }

            if (enumerator.Current.Failed)
            {
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(enumerator.Current.Exception);
                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           diagnostics: new CosmosDiagnosticsContextCore()));
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> crossFeedRangePage = enumerator.Current.Result;

            Pagination.ChangeFeedPage changeFeedPage = crossFeedRangePage.Page;
            ResponseMessage           responseMessage;

            if (changeFeedPage is Pagination.ChangeFeedSuccessPage changeFeedSuccessPage)
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.OK)
                {
                    Content = changeFeedSuccessPage.Content
                };
            }
            else
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.NotModified);
            }

            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState = crossFeedRangePage.State;
            string continuationToken;

            if (this.changeFeedRequestOptions.EmitOldContinuationToken)
            {
                List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>();
                for (int i = 0; i < crossFeedRangeState.Value.Length; i++)
                {
                    FeedRangeState <ChangeFeedState> changeFeedFeedRangeState = crossFeedRangeState.Value.Span[i];
                    string token = changeFeedFeedRangeState.State is ChangeFeedStateContinuation changeFeedStateContinuation ? ((CosmosString)changeFeedStateContinuation.ContinuationToken).Value : null;
                    Documents.Routing.Range <string> range = ((FeedRangeEpk)changeFeedFeedRangeState.FeedRange).Range;
                    CompositeContinuationToken       compositeContinuationToken = new CompositeContinuationToken()
                    {
                        Range = range,
                        Token = token,
                    };

                    compositeContinuationTokens.Add(compositeContinuationToken);
                }

                FeedRangeCompositeContinuation feedRangeCompositeContinuationToken = new FeedRangeCompositeContinuation(
                    await this.documentContainer.GetResourceIdentifierAsync(cancellationToken),
                    FeedRangeEpk.FullRange,
                    compositeContinuationTokens);

                continuationToken = feedRangeCompositeContinuationToken.ToString();
            }
            else
            {
                ChangeFeedCrossFeedRangeState changeFeedCrossFeedRangeState = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
                continuationToken = VersionedAndRidCheckedCompositeToken.ToCosmosElement(
                    new VersionedAndRidCheckedCompositeToken(
                        VersionedAndRidCheckedCompositeToken.Version.V2,
                        changeFeedCrossFeedRangeState.ToCosmosElement(),
                        await this.documentContainer.GetResourceIdentifierAsync(cancellationToken))).ToString();
            }

            responseMessage.Headers.ContinuationToken = continuationToken;
            responseMessage.Headers.RequestCharge     = changeFeedPage.RequestCharge;
            responseMessage.Headers.ActivityId        = changeFeedPage.ActivityId;

            return(responseMessage);
        }
Esempio n. 25
0
 public static ChangeFeedPage CreateNotModifiedPage(double requestCharge, string activityId, ChangeFeedCrossFeedRangeState state)
 {
     return(new ChangeFeedPage(CosmosArray.Empty, notModified: true, requestCharge, activityId, state));
 }
Esempio n. 26
0
 public static ChangeFeedPage CreatePageWithChanges(CosmosArray documents, double requestCharge, string activityId, ChangeFeedCrossFeedRangeState state)
 {
     return(new ChangeFeedPage(documents, notModified: false, requestCharge, activityId, state));
 }