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(); }
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(); }
/// <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; }