/// <summary>
        /// Accepts a restock request and changes the Actor's state accordingly. The request is processed
        /// async and the caller will be notified when the processing is done. 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task AddRestockRequestAsync(RestockRequest request)
        {
            RestockRequestActorState state = await this.StateManager.GetStateAsync<RestockRequestActorState>(ActorStatePropertyName);

            if (state.IsStarted()) //Don't accept a request that is already started
            {
                ActorEventSource.Current.Message(string.Format("RestockRequestActor: {0}: Can't accept restock request in this state", state));
                throw new InvalidOperationException(string.Format("{0}: Can't accept restock request in this state", state));
            }

            // Accept the request
            ActorEventSource.Current.ActorMessage(this, "RestockRequestActor: Accept update quantity request {0}", request);

            state.Status = RestockRequestStatus.Accepted;
            state.Request = request;

            await this.StateManager.SetStateAsync<RestockRequestActorState>(ActorStatePropertyName, state);

            // Start a reminder to go through the processing pipeline.
            // A reminder keeps the actor from being garbage collected due to lack of use, 
            // which works better than a timer in this case.
            await this.RegisterReminderAsync(
                RestockRequestReminderNames.RestockPipelineChangeReminderName,
                null,
                PipelineStageVerificationDelay,
                PipelineStageProcessingDuration);

            return;
        }
        /// <summary>
        /// This method uses an IReliableQueue to store completed RestockRequests which are later sent to the client using batch processing.
        /// We could send the request immediately but we prefer to minimize traffic back to the Inventory Service by batching multiple requests
        /// in one trip. 
        /// </summary>
        /// <param name="actorId"></param>
        /// <param name="request"></param>
        public async void RestockRequestCompleted(ActorId actorId, RestockRequest request)
        {
            IReliableQueue<RestockRequest> completedRequests = await this.StateManager.GetOrAddAsync<IReliableQueue<RestockRequest>>(CompletedRequestsQueueName);

            using (ITransaction tx = this.StateManager.CreateTransaction())
            {
                await completedRequests.EnqueueAsync(tx, request);
                await tx.CommitAsync();
            }

            IRestockRequestActor restockRequestActor = ActorProxy.Create<IRestockRequestActor>(actorId, this.ApplicationName);
            await restockRequestActor.UnsubscribeAsync<IRestockRequestEvents>(this); //QUESTION:What does this method do?
        }
        /// <summary>
        /// This method activates an actor to fulfill the RestockRequest.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task AddRestockRequestAsync(RestockRequest request)
        {
            try
            {
                //Get dictionary of Restock Requests
                IReliableDictionary<InventoryItemId, ActorId> requestDictionary =
                    await this.StateManager.GetOrAddAsync<IReliableDictionary<InventoryItemId, ActorId>>(ItemIdToActorIdMapName);

                ActorId actorId = ActorId.NewId();

                try
                {
                    using (ITransaction tx = this.StateManager.CreateTransaction())
                    {
                        await requestDictionary.AddAsync(tx, request.ItemId, actorId);
                        await tx.CommitAsync();
                    }
                }
                catch (ArgumentException)
                {
                    // restock request already exists
                    return;
                }

                // Create actor proxy and send the request
                IRestockRequestActor restockRequestActor = ActorProxy.Create<IRestockRequestActor>(actorId, this.ApplicationName);

                await restockRequestActor.AddRestockRequestAsync(request);

                // Successfully added, register for event notifications for completion
                await restockRequestActor.SubscribeAsync<IRestockRequestEvents>(this);

                ServiceEventSource.Current.ServiceMessage(this, "Created restock request. Item ID: {0}. Actor ID: {1}", request.ItemId, actorId);
            }
            catch (InvalidOperationException ex)
            {
                ServiceEventSource.Current.Message(string.Format("RestockRequestManagerService: Actor rejected {0}: {1}", request, ex));
                throw;
            }
            catch (Exception ex)
            {
                ServiceEventSource.Current.Message(string.Format("RestockRequestManagerService: Exception {0}: {1}", request, ex));
                throw;
            }
        }
        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);
            }
        }