Example #1
0
        /// <summary>
        /// Starts a multi-threaded queue listener that uses the specified number of dequeue threads.
        /// </summary>
        /// <param name="threadCount">The number of dequeue threads.</param>
        public void StartListener(int threadCount)
        {
            Guard.ArgumentNotZeroOrNegativeValue(threadCount, "threadCount");

            var callToken = TraceManager.WorkerRoleComponent.TraceIn(this.queueLocation.StorageAccount, this.queueLocation.QueueName, threadCount);

            try
            {
                // The collection of dequeue tasks needs to be reset on each call to this method.
                if (this.dequeueTasks.IsAddingCompleted)
                {
                    this.dequeueTasks = new BlockingCollection <Task>(this.dequeueTaskList);
                }

                for (int i = 0; i < threadCount; i++)
                {
                    CancellationToken cancellationToken = this.cancellationSignal.Token;
                    CloudQueueListenerDequeueTaskState <T> workerState = new CloudQueueListenerDequeueTaskState <T>(Subscriptions, cancellationToken, this.queueLocation, this.queueStorage);

                    // Start a new dequeue task and register it in the collection of tasks internally managed by this component.
                    this.dequeueTasks.Add(Task.Factory.StartNew(DequeueTaskMain, workerState, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default));
                }

                // Mark this collection as not accepting any more additions.
                this.dequeueTasks.CompleteAdding();
            }
            finally
            {
                TraceManager.WorkerRoleComponent.TraceOut(callToken);
            }
        }
Example #2
0
        /// <summary>
        /// Implements a task performing dequeue operations against a given Windows Azure queue.
        /// </summary>
        /// <param name="state">An object containing data to be used by the task.</param>
        private void DequeueTaskMain(object state)
        {
            CloudQueueListenerDequeueTaskState <T> workerState = (CloudQueueListenerDequeueTaskState <T>)state;

            var callToken = TraceManager.WorkerRoleComponent.TraceIn(workerState.QueueLocation.StorageAccount, workerState.QueueLocation.QueueName);

            int      idleStateCount = 0;
            TimeSpan sleepInterval  = DequeueInterval;

            try
            {
                // Run a dequeue task until asked to terminate or until a break condition is encountered.
                while (workerState.CanRun)
                {
                    try
                    {
                        var queueMessages = from msg in workerState.QueueStorage.Get <T>(workerState.QueueLocation.QueueName, DequeueBatchSize, workerState.QueueLocation.VisibilityTimeout).AsParallel() where msg != null select msg;
                        int messageCount  = 0;

                        // Check whether or not work items arrived to a queue while the listener was idle.
                        if (idleStateCount > 0 && queueMessages.Count() > 0)
                        {
                            if (QueueWorkDetected != null)
                            {
                                QueueWorkDetected(this);
                            }
                        }

                        // Process the dequeued messages concurrently by taking advantage of the above PLINQ query.
                        queueMessages.ForAll((message) =>
                        {
                            // Reset the count of idle iterations.
                            idleStateCount = 0;

                            // Notify all subscribers that a new message requires processing.
                            workerState.OnNext(message);

                            // Once successful, remove the processed message from the queue.
                            workerState.QueueStorage.Delete <T>(message);

                            // Increment the number of processed messages.
                            messageCount++;
                        });

                        // Check whether or not we have done any work during this iteration.
                        if (0 == messageCount)
                        {
                            // Increment the number of iterations when we were not doing any work (e.g. no messages were dequeued).
                            idleStateCount++;

                            // Call the user-defined delegate informing that no more work is available.
                            if (QueueEmpty != null)
                            {
                                // Check if the user-defined delegate has requested a halt to any further work processing.
                                if (QueueEmpty(this, idleStateCount, out sleepInterval))
                                {
                                    TraceManager.WorkerRoleComponent.TraceInfo(String.Format(CultureInfo.CurrentCulture, TraceLogMessages.CloudQueueListenerTerminatedWithNoMoreWork, this.queueLocation.QueueName, this.queueLocation.StorageAccount));

                                    // Terminate the dequeue loop if user-defined delegate advised us to do so.
                                    break;
                                }
                            }

                            // Enter the idle state for the defined interval.
                            Thread.Sleep(sleepInterval);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (ex is OperationCanceledException)
                        {
                            throw;
                        }
                        else
                        {
                            // Offload the responsibility for handling or reporting the error to the external object.
                            workerState.OnError(ex);

                            // Sleep for the specified interval to avoid a flood of errors.
                            Thread.Sleep(sleepInterval);
                        }
                    }
                }
            }
            finally
            {
                workerState.OnCompleted();
                TraceManager.WorkerRoleComponent.TraceOut(callToken, workerState.QueueLocation.StorageAccount, workerState.QueueLocation.QueueName);
            }
        }