/// <summary> /// Retrieves a customer-specific view (defined in the InventoryItemView class in the Fabrikam Common namespace) /// af all items in the IReliableDictionary in InventoryService. Only items with a CustomerAvailableStock greater than /// zero are returned as a business logic constraint to reduce overordering. /// </summary> /// <returns>IEnumerable of InventoryItemView</returns> public async Task <IEnumerable <InventoryItemView> > GetCustomerInventoryAsync() { IReliableDictionary <InventoryItemId, InventoryItem> inventoryItems = await this.stateManager.GetOrAddAsync <IReliableDictionary <InventoryItemId, InventoryItem> >(InventoryItemDictionaryName); ServiceEventSource.Current.Message("Called GetCustomerInventory to return InventoryItemView"); PrintInventoryItems(inventoryItems); IEnumerable <InventoryItemView> results = inventoryItems.Select(x => (InventoryItemView)x.Value).Where(x => x.CustomerAvailableStock > 0); List <InventoryItemView> resultList = results.ToList <InventoryItemView>(); foreach (InventoryItemView tempResult in resultList) { ServiceEventSource.Current.Message("{0}|{1}", tempResult.Id, tempResult.Description); } return(results); }
private async Task PeriodicInventoryCheck(CancellationToken cancellationToken) { IReliableDictionary <InventoryItemId, InventoryItem> inventoryItems = await this.stateManager.GetOrAddAsync <IReliableDictionary <InventoryItemId, InventoryItem> >(InventoryItemDictionaryName); if (this.storageType == StorageTypes.Azure) { await this.InitializeAsync(cancellationToken); } 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()); } if (this.storageType == StorageTypes.Local) { await this.StateManager.BackupAsync(this.BackupCallbackAsync); } else { await this.StateManager.BackupAsync(this.BackupCallbackAzureAsync); } } await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); } }