public async Task TestRemoveStockWithDuplicateRequest() { int totalStartingStock = 8; int expectedQuantity = 5; int quantityToRemove = 3; MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(stateManager); InventoryItem item = new InventoryItem("test", 1, totalStartingStock, 1, expectedQuantity); await target.CreateInventoryItemAsync(item); CustomerOrderActorMessageId cmid = CustomerOrderActorMessageId.GetRandom(); int actualRemoved = await target.RemoveStockAsync(item.Id, quantityToRemove, cmid); Assert.AreEqual(quantityToRemove, actualRemoved); Assert.AreEqual(expectedQuantity, item.AvailableStock); //save the current availablestock so we can check to be sure it doesn't change int priorAvailableStock = item.AvailableStock; //but now lets say that the reciever didn't get the response and so sends the exact same request again int actualRemoved2 = await target.RemoveStockAsync(item.Id, quantityToRemove, cmid); //in this case the response for the amount removed should be the same Assert.AreEqual(actualRemoved, actualRemoved2); //also, since the request was a duplicate the remaining invintory should be the same as it was before. Assert.AreEqual(item.AvailableStock, priorAvailableStock); }
public async Task TestCreateAndIsItemInInventoryAsync() { MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(stateManager); InventoryItem expected = new InventoryItem("test", 1, 10, 1, 10); await target.CreateInventoryItemAsync(expected); bool resultTrue = await target.IsItemInInventoryAsync(expected.Id); bool resultFalse = await target.IsItemInInventoryAsync(new InventoryItemId()); Assert.IsTrue(resultTrue); Assert.IsFalse(resultFalse); }
/// <summary> /// Used internally to generate inventory items and adds them to the ReliableDict we have. /// </summary> /// <param name="item"></param> /// <returns></returns> public async Task<bool> CreateInventoryItemAsync(InventoryItem item) { IReliableDictionary<InventoryItemId, InventoryItem> inventoryItems = await this.stateManager.GetOrAddAsync<IReliableDictionary<InventoryItemId, InventoryItem>>(InventoryItemDictionaryName); using (ITransaction tx = this.stateManager.CreateTransaction()) { await inventoryItems.AddAsync(tx, item.Id, item); await tx.CommitAsync(); ServiceEventSource.Current.ServiceMessage(this, "Created inventory item: {0}", item); } return true; }
public async Task TestRemoveStock() { int expectedQuantity = 5; int quantityToRemove = 3; MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(stateManager); InventoryItem item = new InventoryItem("test", 1, expectedQuantity + quantityToRemove, 1, expectedQuantity); await target.CreateInventoryItemAsync(item); int actualRemoved = await target.RemoveStockAsync(item.Id, quantityToRemove, CustomerOrderActorMessageId.GetRandom()); Assert.AreEqual(quantityToRemove, actualRemoved); Assert.AreEqual(expectedQuantity, item.AvailableStock); }
public async Task TestAddStock() { int expectedQuantity = 10; int quantityToAdd = 3; MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(statefulServiceContext, stateManager); InventoryItem item = new InventoryItem("test", 1, expectedQuantity - quantityToAdd, 1, expectedQuantity); RestockRequest.Domain.RestockRequest request = new RestockRequest.Domain.RestockRequest(item.Id, quantityToAdd); await target.CreateInventoryItemAsync(item); int actualAdded = await target.AddStockAsync(request.ItemId, quantityToAdd); Assert.AreEqual(quantityToAdd, actualAdded); Assert.AreEqual(item.AvailableStock, expectedQuantity); }
public Task<bool> CreateInventoryItem(string description, decimal price, int number, int reorderThreshold, int max) { InventoryItem i = new InventoryItem(description, price, number, reorderThreshold, max); ServiceUriBuilder builder = new ServiceUriBuilder(InventoryServiceName); IInventoryService inventoryServiceClient = ServiceProxy.Create<IInventoryService>(builder.ToUri(), i.Id.GetPartitionKey()); try { return inventoryServiceClient.CreateInventoryItemAsync(i); } catch (Exception ex) { ServiceEventSource.Current.Message("Web Service: Exception creating {0}: {1}", i, ex); throw; } }
public Task<bool> CreateInventoryItemAsync(InventoryItem item) { return this.CreateInventoryItemAsyncFunc(item); }
private async Task PeriodicInventoryCheck(CancellationToken cancellationToken) { IReliableDictionary<InventoryItemId, InventoryItem> inventoryItems = await this.stateManager.GetOrAddAsync<IReliableDictionary<InventoryItemId, InventoryItem>>(InventoryItemDictionaryName); while (!cancellationToken.IsCancellationRequested) { ServiceEventSource.Current.ServiceMessage(this, "Checking inventory stock for {0} items.", await inventoryItems.GetCountAsync()); foreach (InventoryItem item in inventoryItems.Select(x => x.Value)) { cancellationToken.ThrowIfCancellationRequested(); try { //Check if stock is below restockThreshold and if the item is not already on reorder if ((item.AvailableStock <= item.RestockThreshold) && !item.OnReorder) { ServiceUriBuilder builder = new ServiceUriBuilder(RestockRequestManagerServiceName); IRestockRequestManager restockRequestManagerClient = ServiceProxy.Create<IRestockRequestManager>(0, builder.ToUri()); // we reduce the quantity passed in to RestockRequest to ensure we don't overorder RestockRequest newRequest = new RestockRequest(item.Id, (item.MaxStockThreshold - item.AvailableStock)); InventoryItem updatedItem = new InventoryItem( item.Description, item.Price, item.AvailableStock, item.RestockThreshold, item.MaxStockThreshold, item.Id, true); // TODO: this call needs to be idempotent in case we fail to update the InventoryItem after this completes. await restockRequestManagerClient.AddRestockRequestAsync(newRequest); // Write operations take an exclusive lock on an item, which means we can't do anything else with that item while the transaction is open. // If something blocks before the transaction is committed, the open transaction on the item will prevent all operations on it, including reads. // Once the transaction commits, the lock is released and other operations on the item can proceed. // Operations on the transaction all have timeouts to prevent deadlocking an item, // but we should do as little work inside the transaction as possible that is not related to the transaction itself. using (ITransaction tx = this.stateManager.CreateTransaction()) { await inventoryItems.TryUpdateAsync(tx, item.Id, updatedItem, item); await tx.CommitAsync(); } ServiceEventSource.Current.ServiceMessage( this, "Restock order placed. Item ID: {0}. Quantity: {1}", newRequest.ItemId, newRequest.Quantity); } } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this, "Failed to place restock order for item {0}. {1}", item.Id, e.ToString()); } } await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); } }