public override TryCatch <CrossPartitionState <ChangeFeedState> > Visit(ChangeFeedStartFromContinuation startFromContinuation) { string continuationToken = startFromContinuation.Continuation; TryCatch <CosmosArray> monadicCosmosArray = CosmosArray.Monadic.Parse(continuationToken); if (monadicCosmosArray.Failed) { return(TryCatch <CrossPartitionState <ChangeFeedState> > .FromException( new MalformedChangeFeedContinuationTokenException( message : $"Array expected for change feed continuation token: {continuationToken}.", innerException : monadicCosmosArray.Exception))); } CosmosArray cosmosArray = monadicCosmosArray.Result; if (cosmosArray.Count == 0) { return(TryCatch <CrossPartitionState <ChangeFeedState> > .FromException( new MalformedChangeFeedContinuationTokenException( message : $"non empty array expected for change feed continuation token: {continuationToken}."))); } List <(FeedRangeInternal, ChangeFeedState)> rangeAndStates = new List <(FeedRangeInternal, ChangeFeedState)>(); foreach (CosmosElement arrayItem in cosmosArray) { TryCatch <ChangeFeedContinuationToken> monadicChangeFeedContinuationToken = ChangeFeedContinuationToken.MonadicConvertFromCosmosElement(arrayItem); if (monadicChangeFeedContinuationToken.Failed) { return(TryCatch <CrossPartitionState <ChangeFeedState> > .FromException( new MalformedChangeFeedContinuationTokenException( message : $"Failed to parse change feed continuation token: {continuationToken}.", innerException : monadicChangeFeedContinuationToken.Exception))); } ChangeFeedContinuationToken changeFeedContinuationToken = monadicChangeFeedContinuationToken.Result; rangeAndStates.Add((changeFeedContinuationToken.Range, changeFeedContinuationToken.State)); } CrossPartitionState <ChangeFeedState> crossPartitionState = new CrossPartitionState <ChangeFeedState>(rangeAndStates); return(TryCatch <CrossPartitionState <ChangeFeedState> > .FromResult(crossPartitionState)); }
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); }