private static async void AddRestockRequestsAsync() { // TODO: need to go to correct partition // For now, the inventory is not partitioned, so always go to first partition IRestockRequestManager restockRequestService = ServiceProxy.Create <IRestockRequestManager>(0, RestockRequestManagerServiceName); IList <Task> tasks = new List <Task>(); for (int i = 0; i < ParallelRequests; i++) { RestockRequest request = GenerateRandomRequest(); Console.WriteLine("Add request {0}", request); tasks.Add(restockRequestService.AddRestockRequestAsync(request)); } await Task.WhenAll(tasks); }
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); } }