public async Task SomeChangesAsync() { IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 1); CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create( documentContainer, ChangeFeedMode.Incremental, new ChangeFeedRequestOptions(), new CrossFeedRangeState <ChangeFeedState>( new FeedRangeState <ChangeFeedState>[] { new FeedRangeState <ChangeFeedState>(FeedRangeEpk.FullRange, ChangeFeedState.Beginning()) }), cancellationToken: default); // First page should be true and skip the 304 not modified Assert.IsTrue(await enumerator.MoveNextAsync()); Assert.IsTrue(enumerator.Current.Succeeded); Assert.IsTrue(enumerator.Current.Result.Page is ChangeFeedSuccessPage); // Second page should surface up the 304 Assert.IsTrue(await enumerator.MoveNextAsync()); Assert.IsTrue(enumerator.Current.Succeeded); Assert.IsTrue(enumerator.Current.Result.Page is ChangeFeedNotModifiedPage); }
private static async Task <int> DrainWithUntilNotModifiedWithContinuationTokens( IDocumentContainer documentContainer, CrossPartitionChangeFeedAsyncEnumerator enumerator) { List <CosmosElement> globalChanges = new List <CosmosElement>(); while (true) { if (!await enumerator.MoveNextAsync()) { throw new InvalidOperationException(); } Assert.IsTrue(enumerator.Current.Succeeded); if (!(enumerator.Current.Result is ChangeFeedSuccessPage changeFeedSuccessPage)) { break; } CosmosArray changes = GetChanges(changeFeedSuccessPage.Content); globalChanges.AddRange(changes); CosmosElement continuationToken = ((ChangeFeedStateContinuation)enumerator.Current.Result.State).ContinuationToken; enumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate( documentContainer, new ChangeFeedRequestOptions(), ChangeFeedStartFrom.ContinuationToken(continuationToken.ToString()), cancellationToken: default).Result; } return(globalChanges.Count); }
private static async Task <int> DrainWithUntilNotModifiedWithContinuationTokens( IDocumentContainer documentContainer, CrossPartitionChangeFeedAsyncEnumerator enumerator) { List <CosmosElement> globalChanges = new List <CosmosElement>(); while (true) { if (!await enumerator.MoveNextAsync()) { throw new InvalidOperationException(); } Assert.IsTrue(enumerator.Current.Succeeded); if (!(enumerator.Current.Result.Page is ChangeFeedSuccessPage changeFeedSuccessPage)) { break; } CosmosArray changes = GetChanges(changeFeedSuccessPage.Content); globalChanges.AddRange(changes); enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create( documentContainer, enumerator.Current.Result.State, ChangeFeedPaginationOptions.Default, cancellationToken: default); } return(globalChanges.Count); }
public async Task SomeChangesAsync() { IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 1); TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate( documentContainer, new ChangeFeedRequestOptions(), ChangeFeedStartFrom.Beginning(), cancellationToken: default); Assert.IsTrue(monadicEnumerator.Succeeded); CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result; // First page should be true and skip the 304 not modified Assert.IsTrue(await enumerator.MoveNextAsync()); Assert.IsTrue(enumerator.Current.Succeeded); Assert.IsTrue(enumerator.Current.Result is ChangeFeedSuccessPage); // Second page should surface up the 304 Assert.IsTrue(await enumerator.MoveNextAsync()); Assert.IsTrue(enumerator.Current.Succeeded); Assert.IsTrue(enumerator.Current.Result is ChangeFeedNotModifiedPage); }
private static async Task <int> DrainUntilNotModifedAsync(CrossPartitionChangeFeedAsyncEnumerator enumerator) { int globalCount = 0; while (await enumerator.MoveNextAsync()) { Assert.IsTrue(enumerator.Current.Succeeded); if (!(enumerator.Current.Result is ChangeFeedSuccessPage changeFeedSuccessPage)) { break; } globalCount += GetResponseCount(changeFeedSuccessPage.Content); } return(globalCount); }
public async Task NoChangesAsync() { IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems: 0); CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create( documentContainer, new CrossFeedRangeState<ChangeFeedState>( new FeedRangeState<ChangeFeedState>[] { new FeedRangeState<ChangeFeedState>(FeedRangeEpk.FullRange, ChangeFeedState.Beginning()) }), ChangeFeedPaginationOptions.Default, cancellationToken: default); Assert.IsTrue(await enumerator.MoveNextAsync()); Assert.IsTrue(enumerator.Current.Succeeded); Assert.IsTrue(enumerator.Current.Result.Page is ChangeFeedNotModifiedPage); Assert.IsNotNull(enumerator.Current.Result.State); }
public async Task NoChangesAsync() { IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 0); TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate( documentContainer, new ChangeFeedRequestOptions(), ChangeFeedStartFrom.Beginning(), cancellationToken: default); Assert.IsTrue(monadicEnumerator.Succeeded); CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result; Assert.IsTrue(await enumerator.MoveNextAsync()); Assert.IsTrue(enumerator.Current.Succeeded); Assert.IsTrue(enumerator.Current.Result is ChangeFeedNotModifiedPage); Assert.IsNotNull(enumerator.Current.Result.State); }
public async Task ChangeFeedAsync() { int numItems = 100; IDocumentContainer documentContainer = await this.CreateDocumentContainerAsync(numItems); CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create( documentContainer, ChangeFeedMode.Incremental, new ChangeFeedRequestOptions() { PageSizeHint = int.MaxValue }, new CrossFeedRangeState <ChangeFeedState>( ChangeFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates), cancellationToken: default); int numChildren = 0; Trace rootTrace; using (rootTrace = Trace.GetRootTrace("Cross Partition Change Feed")) { while (await enumerator.MoveNextAsync(rootTrace)) { numChildren++; if (enumerator.Current.Result.Page is ChangeFeedNotModifiedPage) { break; } } } string traceString = TraceWriter.TraceToText(rootTrace); Console.WriteLine(traceString); Assert.AreEqual(numChildren, rootTrace.Children.Count); }
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); }
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); }
public async Task ScenariosAsync() { List <Input> inputs = new List <Input>(); int startLineNumber; int endLineNumber; //---------------------------------------------------------------- // ReadFeed //---------------------------------------------------------------- { startLineNumber = GetLineNumber(); int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); CrossPartitionReadFeedAsyncEnumerator enumerator = CrossPartitionReadFeedAsyncEnumerator.Create( documentContainer, new CrossFeedRangeState <ReadFeedState>(ReadFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates), new ReadFeedPaginationOptions(pageSizeHint: 10), cancellationToken: default); int numChildren = 1; // One extra since we need to read one past the last user page to get the null continuation. TraceForBaselineTesting rootTrace; using (rootTrace = TraceForBaselineTesting.GetRootTrace()) { while (await enumerator.MoveNextAsync(rootTrace)) { numChildren++; } } Assert.AreEqual(numChildren, rootTrace.Children.Count); endLineNumber = GetLineNumber(); inputs.Add(new Input("ReadFeed", rootTrace, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- //---------------------------------------------------------------- // ChangeFeed //---------------------------------------------------------------- { startLineNumber = GetLineNumber(); int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create( documentContainer, new CrossFeedRangeState <ChangeFeedState>( ChangeFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates), new ChangeFeedPaginationOptions( ChangeFeedMode.Incremental, pageSizeHint: int.MaxValue), cancellationToken: default); int numChildren = 0; TraceForBaselineTesting rootTrace; using (rootTrace = TraceForBaselineTesting.GetRootTrace()) { while (await enumerator.MoveNextAsync(rootTrace)) { numChildren++; if (enumerator.Current.Result.Page is ChangeFeedNotModifiedPage) { break; } } } Assert.AreEqual(numChildren, rootTrace.Children.Count); endLineNumber = GetLineNumber(); inputs.Add(new Input("ChangeFeed", rootTrace, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- //---------------------------------------------------------------- // Query //---------------------------------------------------------------- { startLineNumber = GetLineNumber(); int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); IQueryPipelineStage pipelineStage = CreatePipeline(documentContainer, "SELECT * FROM c", pageSize: 10); TraceForBaselineTesting rootTrace; int numChildren = 1; // One extra since we need to read one past the last user page to get the null continuation. using (rootTrace = TraceForBaselineTesting.GetRootTrace()) { while (await pipelineStage.MoveNextAsync(rootTrace)) { numChildren++; } } Assert.AreEqual(numChildren, rootTrace.Children.Count); endLineNumber = GetLineNumber(); inputs.Add(new Input("Query", rootTrace, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- this.ExecuteTestSuite(inputs); }