/// <summary> /// Implements a callback delegate which will be invoked whenever there is no more work available on the queue. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="idleCount">The value indicating how many times the queue listener has been idle.</param> /// <param name="delay">The time interval during which the queue listener will be instructed to sleep before performing next unit of work.</param> /// <returns>A boolean flag indicating that the queue listener should stop processing any further work and must terminate.</returns> private bool HandleQueueEmptyEvent(object sender, int idleCount, out TimeSpan delay) { // The sender is an instance of the ICloudQueueServiceWorkerRoleExtension, we can safely perform type casting. ICloudQueueServiceWorkerRoleExtension queueService = sender as ICloudQueueServiceWorkerRoleExtension; // Find out which extension is responsible for retrieving the worker role configuration settings. IWorkItemProcessorConfigurationExtension config = Extensions.Find <IWorkItemProcessorConfigurationExtension>(); // Get the current state of the queue listener to determine point-in-time load characteristics. CloudQueueListenerInfo queueServiceState = queueService.QueryState(); // Set up the initial parameters, read configuration settings. int deltaBackoffMs = 100; int minimumIdleIntervalMs = Convert.ToInt32(config.Settings.MinimumIdleInterval.TotalMilliseconds); int maximumIdleIntervalMs = Convert.ToInt32(config.Settings.MaximumIdleInterval.TotalMilliseconds); // Calculate a new sleep interval value that will follow a random exponential back-off curve. int delta = (int)((Math.Pow(2.0, (double)idleCount) - 1.0) * (new Random()).Next((int)(deltaBackoffMs * 0.8), (int)(deltaBackoffMs * 1.2))); int interval = Math.Min(minimumIdleIntervalMs + delta, maximumIdleIntervalMs); // Pass the calculated interval to the dequeue task to enable it to enter into a sleep state for the specified duration. delay = TimeSpan.FromMilliseconds((double)interval); // As soon as interval reaches its maximum, tell the source dequeue task that it must gracefully terminate itself // unless this is a last deqeueue task. If so, we are not going to keep it running and continue polling the queue. return(delay.TotalMilliseconds >= maximumIdleIntervalMs); }
/// <summary> /// Implements a callback delegate to be invoked whenever a new work has arrived to a queue while the queue listener was idle. /// </summary> /// <param name="sender">The source of the event.</param> private void HandleQueueWorkDetectedEvent(object sender) { // The sender is an instance of the ICloudQueueServiceWorkerRoleExtension, we can safely perform type casting. ICloudQueueServiceWorkerRoleExtension queueService = sender as ICloudQueueServiceWorkerRoleExtension; // Get the current state of the queue listener to determine point-in-time load characteristics. CloudQueueListenerInfo queueServiceState = queueService.QueryState(); // Invoke a rule returning the number of queue tasks that would be required to handle the workload in a queue given its current depth. int dequeueTaskCount = GetOptimalDequeueTaskCount(queueServiceState.CurrentQueueDepth); // If the dequeue task count is less than computed above, start as many dequeue tasks as needed. if (queueServiceState.ActiveDequeueTasks < dequeueTaskCount) { // Start the required number of dequeue tasks. queueService.StartListener(dequeueTaskCount - queueServiceState.ActiveDequeueTasks); } }