public SharedBlobQueueProcessor(BlobQueueTriggerExecutor triggerExecutor, QueueClient queue, QueueClient poisonQueue, ILoggerFactory loggerFactory, QueuesOptions queuesOptions)
     : base(new QueueProcessorOptions(queue, loggerFactory, queuesOptions, poisonQueue))
 {
     _executor = triggerExecutor;
 }
        public QueueListener(QueueClient queue,
                             QueueClient poisonQueue,
                             ITriggerExecutor <QueueMessage> triggerExecutor,
                             IWebJobsExceptionHandler exceptionHandler,
                             ILoggerFactory loggerFactory,
                             SharedQueueWatcher sharedWatcher,
                             QueuesOptions queueOptions,
                             IQueueProcessorFactory queueProcessorFactory,
                             FunctionDescriptor functionDescriptor,
                             string functionId           = null,
                             TimeSpan?maxPollingInterval = null)
        {
            if (queueOptions == null)
            {
                throw new ArgumentNullException(nameof(queueOptions));
            }

            if (queueProcessorFactory == null)
            {
                throw new ArgumentNullException(nameof(queueProcessorFactory));
            }

            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            if (queueOptions.BatchSize <= 0)
            {
                throw new ArgumentException("BatchSize must be greater than zero.");
            }

            if (queueOptions.MaxDequeueCount <= 0)
            {
                throw new ArgumentException("MaxDequeueCount must be greater than zero.");
            }

            _timer              = new TaskSeriesTimer(this, exceptionHandler, Task.Delay(0));
            _queue              = queue;
            _poisonQueue        = poisonQueue;
            _triggerExecutor    = triggerExecutor;
            _exceptionHandler   = exceptionHandler;
            _queueOptions       = queueOptions;
            _logger             = loggerFactory.CreateLogger <QueueListener>();
            _functionDescriptor = functionDescriptor ?? throw new ArgumentNullException(nameof(functionDescriptor));
            _functionId         = functionId ?? _functionDescriptor.Id;

            // if the function runs longer than this, the invisibility will be updated
            // on a timer periodically for the duration of the function execution
            _visibilityTimeout = TimeSpan.FromMinutes(10);

            if (sharedWatcher != null)
            {
                // Call Notify whenever a function adds a message to this queue.
                sharedWatcher.Register(queue.Name, this);
                _sharedWatcher = sharedWatcher;
            }

            EventHandler <PoisonMessageEventArgs> poisonMessageEventHandler = _sharedWatcher != null ? OnMessageAddedToPoisonQueue : (EventHandler <PoisonMessageEventArgs>)null;

            _queueProcessor = CreateQueueProcessor(_queue, _poisonQueue, loggerFactory, queueProcessorFactory, _queueOptions, poisonMessageEventHandler);

            TimeSpan maximumInterval = _queueProcessor.MaxPollingInterval;

            if (maxPollingInterval.HasValue && maximumInterval > maxPollingInterval.Value)
            {
                // enforce the maximum polling interval if specified
                maximumInterval = maxPollingInterval.Value;
            }

            _delayStrategy = new RandomizedExponentialBackoffStrategy(SharedQueuePollingIntervals.Minimum, maximumInterval);

            _scaleMonitorDescriptor          = new ScaleMonitorDescriptor($"{_functionId}-QueueTrigger-{_queue.Name}".ToLower(CultureInfo.InvariantCulture));
            _shutdownCancellationTokenSource = new CancellationTokenSource();
        }
Example #3
0
 public SharedBlobQueueProcessorFactory(BlobQueueTriggerExecutor triggerExecutor, CloudQueue queue, ILoggerFactory loggerFactory, QueuesOptions queuesOptions, CloudQueue poisonQueue)
 {
     _triggerExecutor = triggerExecutor;
     _queue           = queue;
     _loggerFactory   = loggerFactory;
     _options         = queuesOptions;
     _poisonQueue     = poisonQueue;
 }
        public void CreateQueueProcessor_CreatesProcessorCorrectly()
        {
            CloudQueue poisonQueue = null;
            bool       poisonMessageHandlerInvoked = false;
            EventHandler <PoisonMessageEventArgs> poisonMessageEventHandler = (sender, e) => { poisonMessageHandlerInvoked = true; };
            Mock <IQueueProcessorFactory>         mockQueueProcessorFactory = new Mock <IQueueProcessorFactory>(MockBehavior.Strict);
            QueuesOptions queueConfig = new QueuesOptions
            {
                MaxDequeueCount = 7
            };
            QueueProcessor expectedQueueProcessor  = null;
            bool           processorFactoryInvoked = false;

            // create for a host queue - don't expect custom factory to be invoked
            CloudQueue     queue          = new CloudQueue(new Uri(string.Format("https://test.queue.core.windows.net/{0}", HostQueueNames.GetHostQueueName("12345"))));
            QueueProcessor queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, _loggerFactory, mockQueueProcessorFactory.Object, queueConfig, poisonMessageEventHandler);

            Assert.False(processorFactoryInvoked);
            Assert.NotSame(expectedQueueProcessor, queueProcessor);
            queueProcessor.OnMessageAddedToPoisonQueue(new PoisonMessageEventArgs(null, poisonQueue));
            Assert.True(poisonMessageHandlerInvoked);

            QueueProcessorFactoryContext processorFactoryContext = null;

            mockQueueProcessorFactory.Setup(p => p.Create(It.IsAny <QueueProcessorFactoryContext>()))
            .Callback <QueueProcessorFactoryContext>((mockProcessorContext) =>
            {
                processorFactoryInvoked = true;

                Assert.Same(queue, mockProcessorContext.Queue);
                Assert.Same(poisonQueue, mockProcessorContext.PoisonQueue);
                Assert.Equal(queueConfig.MaxDequeueCount, mockProcessorContext.MaxDequeueCount);
                Assert.NotNull(mockProcessorContext.Logger);

                processorFactoryContext = mockProcessorContext;
            })
            .Returns(() =>
            {
                expectedQueueProcessor = new QueueProcessor(processorFactoryContext);
                return(expectedQueueProcessor);
            });

            // when storage host is "localhost" we invoke the processor factory even for
            // host queues (this enables local test mocking)
            processorFactoryInvoked = false;
            queue          = new CloudQueue(new Uri(string.Format("https://localhost/{0}", HostQueueNames.GetHostQueueName("12345"))));
            queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, _loggerFactory, mockQueueProcessorFactory.Object, queueConfig, poisonMessageEventHandler);
            Assert.True(processorFactoryInvoked);
            Assert.Same(expectedQueueProcessor, queueProcessor);

            // create for application queue - expect processor factory to be invoked
            poisonMessageHandlerInvoked = false;
            processorFactoryInvoked     = false;
            queue          = new CloudQueue(new Uri("https://test.queue.core.windows.net/testqueue"));
            queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, _loggerFactory, mockQueueProcessorFactory.Object, queueConfig, poisonMessageEventHandler);
            Assert.True(processorFactoryInvoked);
            Assert.Same(expectedQueueProcessor, queueProcessor);
            queueProcessor.OnMessageAddedToPoisonQueue(new PoisonMessageEventArgs(null, poisonQueue));
            Assert.True(poisonMessageHandlerInvoked);

            // if poison message watcher not specified, event not subscribed to
            poisonMessageHandlerInvoked = false;
            processorFactoryInvoked     = false;
            queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, _loggerFactory, mockQueueProcessorFactory.Object, queueConfig, null);
            Assert.True(processorFactoryInvoked);
            Assert.Same(expectedQueueProcessor, queueProcessor);
            queueProcessor.OnMessageAddedToPoisonQueue(new PoisonMessageEventArgs(null, poisonQueue));
            Assert.False(poisonMessageHandlerInvoked);
        }
 /// <summary>
 /// Constructs a new instance.
 /// </summary>
 /// <param name="queue">The queue the <see cref="QueueProcessor"/> will operate on.</param>
 /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to create an <see cref="ILogger"/> from.</param>
 /// <param name="options">The queue configuration.</param>
 /// <param name="poisonQueue">The queue to move messages to when unable to process a message after the maximum dequeue count has been exceeded. May be null.</param>
 internal QueueProcessorOptions(QueueClient queue, ILoggerFactory loggerFactory, QueuesOptions options, QueueClient poisonQueue = null)
 {
     Queue       = queue ?? throw new ArgumentNullException(nameof(queue));
     PoisonQueue = poisonQueue;
     Logger      = loggerFactory?.CreateLogger <QueueProcessor>();
     Options     = options.Clone();
 }
Example #6
0
 /// <summary>
 /// Constructs a new instance.
 /// </summary>
 /// <param name="queue">The queue the <see cref="QueueProcessor"/> will operate on.</param>
 /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to create an <see cref="ILogger"/> from.</param>
 /// <param name="options">The queue configuration.</param>
 /// <param name="poisonQueue">The queue to move messages to when unable to process a message after the maximum dequeue count has been exceeded. May be null.</param>
 internal QueueProcessorOptions(QueueClient queue, ILoggerFactory loggerFactory, QueuesOptions options, QueueClient poisonQueue = null)
 {
     Queue       = queue ?? throw new ArgumentNullException(nameof(queue));
     PoisonQueue = poisonQueue;
     Logger      = loggerFactory?.CreateLogger(LogCategories.CreateTriggerCategory("Queue"));
     Options     = options;
 }
 /// <summary>
 /// Constructs a new instance.
 /// </summary>
 /// <param name="queue">TODO.</param>
 /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to create an <see cref="ILogger"/> from.</param>
 /// <param name="options">The queue configuration.</param>
 /// <param name="poisonQueue">The queue to move messages to when unable to process a message after the maximum dequeue count has been exceeded. May be null.</param>
 // TODO (kasobol-msft) this was internal before check this.
 public QueueProcessorFactoryContext(QueueClient queue, ILoggerFactory loggerFactory, QueuesOptions options, QueueClient poisonQueue = null)
     : this(queue, loggerFactory, poisonQueue)
 {
     BatchSize          = options.BatchSize;
     MaxDequeueCount    = options.MaxDequeueCount;
     NewBatchThreshold  = options.NewBatchThreshold;
     VisibilityTimeout  = options.VisibilityTimeout;
     MaxPollingInterval = options.MaxPollingInterval;
 }