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 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 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); }
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 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 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); }