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);
        }
Beispiel #2
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()));
            }

            ChangeFeedPage  changeFeedPage = enumerator.Current.Result;
            ResponseMessage responseMessage;

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

            CosmosElement innerContinuationToken = ((ChangeFeedStateContinuation)changeFeedPage.State).ContinuationToken;
            string        continuationToken;

            if (this.changeFeedRequestOptions.EmitOldContinuationToken)
            {
                List <ChangeFeedContinuationToken> parsedChangeFeedTokens = new List <ChangeFeedContinuationToken>();
                CosmosArray changeFeedTokens = (CosmosArray)innerContinuationToken;
                foreach (CosmosElement changeFeedToken in changeFeedTokens)
                {
                    parsedChangeFeedTokens.Add(ChangeFeedContinuationToken.MonadicConvertFromCosmosElement(changeFeedToken).Result);
                }

                List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>();
                foreach (ChangeFeedContinuationToken changeFeedContinuationToken in parsedChangeFeedTokens)
                {
                    string token = changeFeedContinuationToken.State is ChangeFeedStateContinuation changeFeedStateContinuation ? ((CosmosString)changeFeedStateContinuation.ContinuationToken).Value : null;
                    Documents.Routing.Range <string> range = ((FeedRangeEpk)changeFeedContinuationToken.Range).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
            {
                continuationToken = VersionedAndRidCheckedCompositeToken.ToCosmosElement(
                    new VersionedAndRidCheckedCompositeToken(
                        VersionedAndRidCheckedCompositeToken.Version.V2,
                        innerContinuationToken,
                        await this.documentContainer.GetResourceIdentifierAsync(cancellationToken))).ToString();
            }

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

            return(responseMessage);
        }