private static async Task VerifyExceptionThrownOnExecuteAsync( TransactionalBatch batch, Type expectedTypeOfException, string expectedExceptionMessage = null, TransactionalBatchRequestOptions requestOptions = null) { bool wasExceptionThrown = false; try { if (requestOptions != null) { await batch.ExecuteAsync(requestOptions); } else { await batch.ExecuteAsync(); } } catch (Exception ex) { Assert.AreEqual(expectedTypeOfException, ex.GetType()); if (expectedExceptionMessage != null) { Assert.IsTrue(ex.Message.Contains(expectedExceptionMessage)); } wasExceptionThrown = true; } if (!wasExceptionThrown) { Assert.Fail("Exception was expected to be thrown but was not."); } }
public async Task ItemBatchNoResponseTest() { TransactionalBatchItemRequestOptions requestOptions = new TransactionalBatchItemRequestOptions() { EnableContentResponseOnWrite = false }; string pkId = "TestBatchId"; TransactionalBatch batch = this.container.CreateTransactionalBatch(new PartitionKey(pkId)); int noResponseItemCount = 100; for (int i = 0; i < noResponseItemCount; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId); batch.CreateItem <ToDoActivity>(item, requestOptions: requestOptions); } TransactionalBatchResponse response = await batch.ExecuteAsync(); Assert.AreEqual(100, response.Count); this.ValidateResponse(response, noResponseItemCount); pkId = "TestBatchId2"; batch = this.container.CreateTransactionalBatch(new PartitionKey(pkId)); noResponseItemCount = 0; for (int i = 0; i < 10; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId); batch.CreateItem <ToDoActivity>(item, requestOptions: requestOptions); noResponseItemCount++; ToDoActivity item2 = ToDoActivity.CreateRandomToDoActivity(pk: pkId); item2.id = item.id; batch.ReplaceItem <ToDoActivity>(item2.id, item2, requestOptions); noResponseItemCount++; } int withBodyCount = 0; for (int i = 0; i < 5; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId); batch.CreateItem <ToDoActivity>(item); withBodyCount++; batch.ReadItem(item.id); withBodyCount++; } response = await batch.ExecuteAsync(); Assert.AreEqual(noResponseItemCount + withBodyCount, response.Count); this.ValidateResponse(response, noResponseItemCount); }
public async Task NoContentResponseTransactionBatchOverrideTest() { string pkId = "TestBatchId"; TransactionalBatch batch = this.containerWithFlag.CreateTransactionalBatch(new PartitionKey(pkId)); TransactionalBatchItemRequestOptions requestOptions = new TransactionalBatchItemRequestOptions() { EnableContentResponseOnWrite = false }; int noResponseItemCount = 100; for (int i = 0; i < noResponseItemCount; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkId); batch.CreateItem <ToDoActivity>(item, requestOptions: requestOptions); } TransactionalBatchResponse response = await batch.ExecuteAsync(); Assert.AreEqual(response.Count, 100); foreach (TransactionalBatchOperationResult itemResponse in response) { Assert.IsTrue(itemResponse.StatusCode == HttpStatusCode.Created); Assert.IsNull(itemResponse.ResourceStream); } }
public async Task BatchOperationDiagnostic(bool disableDiagnostics) { string pkValue = "DiagnosticTestPk"; TransactionalBatch batch = this.Container.CreateTransactionalBatch(new PartitionKey(pkValue)); BatchCore batchCore = (BatchCore)batch; List <PatchOperation> patch = new List <PatchOperation>() { PatchOperation.Remove("/cost") }; List <ToDoActivity> createItems = new List <ToDoActivity>(); for (int i = 0; i < 50; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkValue); createItems.Add(item); batch.CreateItem <ToDoActivity>(item); } for (int i = 0; i < 20; i++) { batch.ReadItem(createItems[i].id); batchCore.PatchItem(createItems[i].id, patch); } TransactionalBatchRequestOptions requestOptions = disableDiagnostics ? RequestOptionDisableDiagnostic : null; TransactionalBatchResponse response = await batch.ExecuteAsync(requestOptions); Assert.IsNotNull(response); CosmosDiagnosticsTests.VerifyPointDiagnostics( diagnostics: response.Diagnostics, disableDiagnostics: disableDiagnostics); }
public async Task ExecuteAsync(Container collection) { EnsureArg.IsNotNull(collection, nameof(collection)); // Detect if registry has been initialized var partitionKey = new PartitionKey(SearchParameterStatusWrapper.SearchParameterStatusPartitionKey); var query = _queryFactory.Create <dynamic>( collection, new CosmosQueryContext( new QueryDefinition($"SELECT TOP 1 * FROM c where c.{KnownDocumentProperties.PartitionKey} = '{SearchParameterStatusWrapper.SearchParameterStatusPartitionKey}'"), new QueryRequestOptions { PartitionKey = partitionKey })); var results = await query.ExecuteNextAsync(); if (!results.Any()) { var statuses = await _filebasedRegistry.GetSearchParameterStatuses(); foreach (var batch in statuses.TakeBatch(100)) { TransactionalBatch transaction = collection.CreateTransactionalBatch(partitionKey); foreach (SearchParameterStatusWrapper status in batch.Select(x => x.ToSearchParameterStatusWrapper())) { transaction.CreateItem(status); } await transaction.ExecuteAsync(); } } }
internal static async Task ExecuteOperationsAsync <TOperation>(this TransactionalBatch transactionalBatch, Dictionary <int, TOperation> operationMappings, PartitionKeyPath partitionKeyPath, CancellationToken cancellationToken = default) where TOperation : IOperation { foreach (var operation in operationMappings.Values) { operation.Apply(transactionalBatch, partitionKeyPath); } using (var batchOutcomeResponse = await transactionalBatch.ExecuteAsync(cancellationToken).ConfigureAwait(false)) { for (var i = 0; i < batchOutcomeResponse.Count; i++) { var result = batchOutcomeResponse[i]; operationMappings.TryGetValue(i, out var operation); IOperation operationToBeExecuted = operation ?? ThrowOnConflictOperation.Instance; if (result.IsSuccessStatusCode) { operationToBeExecuted.Success(result); continue; } // guaranteed to throw operationToBeExecuted.Conflict(result); } } }
/// <inheritdoc /> public async ValueTask UpdateAsBatchAsync( IEnumerable <TItem> items, CancellationToken cancellationToken = default) { List <TItem> list = items.ToList(); string partitionKey = GetPartitionKeyValue(list); Container container = await _containerProvider.GetContainerAsync(); TransactionalBatch batch = container.CreateTransactionalBatch(new PartitionKey(partitionKey)); foreach (TItem item in list) { TransactionalBatchItemRequestOptions options = new(); if (item is IItemWithEtag itemWithEtag) { options.IfMatchEtag = itemWithEtag.Etag; } batch.UpsertItem(item, options); } using TransactionalBatchResponse response = await batch.ExecuteAsync(cancellationToken); if (!response.IsSuccessStatusCode) { throw new BatchOperationException <TItem>(response); } }
public async Task TestDispose() { CosmosClient cosmosClient = new CosmosClient(ConnectionString); Database database = cosmosClient.GetDatabase("asdf"); Container container = cosmosClient.GetContainer("asdf", "asdf"); TransactionalBatch batch = container.CreateTransactionalBatch(new PartitionKey("asdf")); batch.ReadItem("Test"); FeedIterator <dynamic> feedIterator1 = container.GetItemQueryIterator <dynamic>(); FeedIterator <dynamic> feedIterator2 = container.GetItemQueryIterator <dynamic>(queryText: "select * from T"); FeedIterator <dynamic> feedIterator3 = database.GetContainerQueryIterator <dynamic>(queryText: "select * from T"); string userAgent = cosmosClient.ClientContext.UserAgent; // Dispose should be idempotent cosmosClient.Dispose(); cosmosClient.Dispose(); List <Func <Task> > validateAsync = new List <Func <Task> >() { () => cosmosClient.ReadAccountAsync(), () => cosmosClient.CreateDatabaseAsync("asdf"), () => database.CreateContainerAsync("asdf", "/pkpathasdf", 200), () => container.ReadItemAsync <dynamic>("asdf", new PartitionKey("test")), () => container.Scripts.ReadStoredProcedureAsync("asdf"), () => container.Scripts.ReadTriggerAsync("asdf"), () => container.Scripts.ReadUserDefinedFunctionAsync("asdf"), () => batch.ExecuteAsync(), () => feedIterator1.ReadNextAsync(), () => feedIterator2.ReadNextAsync(), () => feedIterator3.ReadNextAsync(), }; foreach (Func <Task> asyncFunc in validateAsync) { try { await asyncFunc(); Assert.Fail("Should throw ObjectDisposedException"); } catch (CosmosObjectDisposedException e) { string expectedMessage = $"Cannot access a disposed 'CosmosClient'. Follow best practices and use the CosmosClient as a singleton." + $" CosmosClient was disposed at: {cosmosClient.DisposedDateTimeUtc.Value.ToString("o", CultureInfo.InvariantCulture)}; CosmosClient Endpoint: https://localtestcosmos.documents.azure.com/; Created at: {cosmosClient.ClientConfigurationTraceDatum.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)}; UserAgent: {userAgent};"; Assert.IsTrue(e.Message.Contains(expectedMessage)); string diagnostics = e.Diagnostics.ToString(); Assert.IsNotNull(diagnostics); Assert.IsFalse(diagnostics.Contains("NoOp")); Assert.IsTrue(diagnostics.Contains("Client Configuration")); string exceptionString = e.ToString(); Assert.IsTrue(exceptionString.Contains(diagnostics)); Assert.IsTrue(exceptionString.Contains(e.Message)); Assert.IsTrue(exceptionString.Contains(e.StackTrace)); } } }
public async Task TestDispose() { CosmosClient cosmosClient = new CosmosClient(ConnectionString); Database database = cosmosClient.GetDatabase("asdf"); Container container = cosmosClient.GetContainer("asdf", "asdf"); TransactionalBatch batch = container.CreateTransactionalBatch(new PartitionKey("asdf")); batch.ReadItem("Test"); // Dispose should be idempotent cosmosClient.Dispose(); cosmosClient.Dispose(); List <Func <Task> > validateAsync = new List <Func <Task> >() { () => cosmosClient.ReadAccountAsync(), () => cosmosClient.CreateDatabaseAsync("asdf"), () => database.CreateContainerAsync("asdf", "/pkpathasdf", 200), () => container.ReadItemAsync <dynamic>("asdf", new PartitionKey("test")), () => container.Scripts.ReadStoredProcedureAsync("asdf"), () => container.Scripts.ReadTriggerAsync("asdf"), () => container.Scripts.ReadUserDefinedFunctionAsync("asdf"), () => batch.ExecuteAsync(), () => container.GetItemQueryIterator <dynamic>(queryText: "select * from T").ReadNextAsync(), () => container.GetItemQueryIterator <dynamic>().ReadNextAsync(), }; foreach (Func <Task> asyncFunc in validateAsync) { try { await asyncFunc(); Assert.Fail("Should throw ObjectDisposedException"); } catch (ObjectDisposedException) { } } }
public async Task ExecuteAsync(Container container, CancellationToken cancellationToken) { EnsureArg.IsNotNull(container, nameof(container)); // Detect if registry has been initialized var partitionKey = new PartitionKey(SearchParameterStatusWrapper.SearchParameterStatusPartitionKey); var query = _queryFactory.Create <dynamic>( container, new CosmosQueryContext( new QueryDefinition($"SELECT TOP 1 * FROM c where c.{KnownDocumentProperties.PartitionKey} = '{SearchParameterStatusWrapper.SearchParameterStatusPartitionKey}'"), new QueryRequestOptions { PartitionKey = partitionKey })); var results = await query.ExecuteNextAsync(cancellationToken); if (!results.Any()) { var statuses = await _filebasedSearchParameterStatusDataStore.GetSearchParameterStatuses(cancellationToken); foreach (var status in statuses.Where(x => _configuration.InitialSortParameterUris.Contains(x.Uri.OriginalString))) { status.SortStatus = SortParameterStatus.Enabled; } foreach (var batch in statuses.TakeBatch(100)) { TransactionalBatch transaction = container.CreateTransactionalBatch(partitionKey); foreach (SearchParameterStatusWrapper status in batch.Select(x => x.ToSearchParameterStatusWrapper())) { transaction.CreateItem(status); } await transaction.ExecuteAsync(cancellationToken); } } }
public async Task UpsertStatuses(IReadOnlyCollection <ResourceSearchParameterStatus> statuses) { EnsureArg.IsNotNull(statuses, nameof(statuses)); if (statuses.Count == 0) { return; } foreach (IEnumerable <ResourceSearchParameterStatus> statusBatch in statuses.TakeBatch(100)) { using IScoped <Container> clientScope = _containerScopeFactory.Invoke(); TransactionalBatch batch = clientScope.Value.CreateTransactionalBatch(new PartitionKey(SearchParameterStatusWrapper.SearchParameterStatusPartitionKey)); foreach (SearchParameterStatusWrapper status in statusBatch.Select(x => x.ToSearchParameterStatusWrapper())) { status.LastUpdated = Clock.UtcNow; batch.UpsertItem(status); } await batch.ExecuteAsync(); } }
internal static async Task ExecuteOperationAsync(this TransactionalBatch transactionalBatch, IOperation operation, PartitionKeyPath partitionKeyPath, CancellationToken cancellationToken = default) { operation.Apply(transactionalBatch, partitionKeyPath); using (var batchOutcomeResponse = await transactionalBatch.ExecuteAsync(cancellationToken).ConfigureAwait(false)) { if (batchOutcomeResponse.Count > 1) { throw new Exception($"The transactional batch was expected to have a single operation but contained {batchOutcomeResponse.Count} operations."); } var result = batchOutcomeResponse[0]; if (result.IsSuccessStatusCode) { operation.Success(result); return; } // guaranteed to throw operation.Conflict(result); } }
async Task CreateOrUpdateInBatch(TransactionalBatch batch) { if (etag == null) { batch.CreateItemStream(ToStream(value)); } else { var options = new TransactionalBatchItemRequestOptions { IfMatchEtag = etag }; batch.ReplaceItemStream(TransactionEntityId, ToStream(value), options); } var response = await batch.ExecuteAsync().ConfigureAwait(false); if (!response.IsSuccessStatusCode) { throw new Exception(response.ToString()); } etag = response.Last().ETag; }
public async Task BatchOperationDiagnostic() { string pkValue = "DiagnosticTestPk"; TransactionalBatch batch = this.Container.CreateTransactionalBatch(new PartitionKey(pkValue)); List <ToDoActivity> createItems = new List <ToDoActivity>(); for (int i = 0; i < 50; i++) { ToDoActivity item = ToDoActivity.CreateRandomToDoActivity(pk: pkValue); createItems.Add(item); batch.CreateItem <ToDoActivity>(item); } for (int i = 0; i < 20; i++) { batch.ReadItem(createItems[i].id); } TransactionalBatchResponse response = await batch.ExecuteAsync(); Assert.IsNotNull(response); CosmosDiagnosticsTests.VerifyPointDiagnostics(response.Diagnostics); }
public async ValueTask DeleteAsBatchAsync( IEnumerable <TItem> items, CancellationToken cancellationToken = default) { List <TItem> list = items.ToList(); string partitionKey = GetPartitionKeyValue(list); Container container = await _containerProvider.GetContainerAsync(); TransactionalBatch batch = container.CreateTransactionalBatch(new PartitionKey(partitionKey)); foreach (TItem item in list) { batch.DeleteItem(item.Id); } using TransactionalBatchResponse response = await batch.ExecuteAsync(cancellationToken); if (!response.IsSuccessStatusCode) { throw new BatchOperationException <TItem>(response); } }