Ejemplo n.º 1
0
        public Task <IListener> CreateAsync(CancellationToken cancellationToken)
        {
            QueueTriggerExecutor triggerExecutor = new QueueTriggerExecutor(_executor);

            SharedQueueWatcher sharedWatcher = _sharedContextProvider.GetOrCreateInstance <SharedQueueWatcher>(
                new SharedQueueWatcherFactory(_messageEnqueuedWatcherSetter));

            IListener listener = new QueueListener(_queue, _poisonQueue, triggerExecutor,
                                                   _exceptionHandler, _trace, sharedWatcher, _queueConfiguration);

            return(Task.FromResult(listener));
        }
Ejemplo n.º 2
0
        public Task <IListener> CreateAsync(CancellationToken cancellationToken)
        {
            QueueTriggerExecutor triggerExecutor = new QueueTriggerExecutor(_executor);

            IDelayStrategy delayStrategy = new RandomizedExponentialBackoffStrategy(QueuePollingIntervals.Minimum, _queueConfiguration.MaxPollingInterval);

            SharedQueueWatcher sharedWatcher = _sharedContextProvider.GetOrCreateInstance <SharedQueueWatcher>(
                new SharedQueueWatcherFactory(_messageEnqueuedWatcherSetter));

            IListener listener = new QueueListener(_queue, _poisonQueue, triggerExecutor, delayStrategy,
                                                   _backgroundExceptionDispatcher, _trace, sharedWatcher, _queueConfiguration);

            return(Task.FromResult(listener));
        }
Ejemplo n.º 3
0
        public async Task HotPathNotificationTest()
        {
            await _sharedQueue.InitializeAsync(CancellationToken.None);

            var messageHandlerMock = new Mock <IMessageHandler>();
            var calls = 0;

            messageHandlerMock.Setup(m => m.TryExecuteAsync(It.IsAny <JObject>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() =>
            {
                calls++;     // executed sequentially, no need interlocked
                return(new FunctionResult(true));
            });

            Assert.True(_sharedQueue.RegisterHandler("mockFunction1", messageHandlerMock.Object));

            // register another INotificationHandler to sharedQueueWatcher
            // so that we can tell when the sharedQueueListener is notified
            var notifies         = 0;
            var notificationMock = new Mock <INotificationCommand>();

            notificationMock.Setup(m => m.Notify()).Callback(() => Interlocked.Increment(ref notifies));
            _sharedContextProvider.GetOrCreateInstance <SharedQueueWatcher>(null)
            .Register(HostQueueNames.GetHostSharedQueueName(HostId), notificationMock.Object);

            await _sharedQueue.StartQueueAsync(CancellationToken.None);

            int max     = 10;
            var enqueue = new List <Task>();

            for (int i = 0; i < max; i++)
            {
                JObject message = JObject.Parse("{count:" + i + "}");
                enqueue.Add(_sharedQueue.EnqueueAsync(message, "mockFunction1", CancellationToken.None));
            }

            await Task.WhenAll(enqueue);

            // wait for dequeue
            await TestHelpers.Await(() => calls >= max, 1000, 200);

            await _sharedQueue.StopQueueAsync(CancellationToken.None);

            Assert.Equal(max, notifies);
            Assert.Equal(max, calls);
        }
        public async Task <IListener> CreateAsync(CancellationToken cancellationToken)
        {
            // Note that these clients are intentionally for the storage account rather than for the dashboard account.
            // We use the storage, not dashboard, account for the blob receipt container and blob trigger queues.
            var primaryQueueClient = _hostQueueServiceClient;
            var primaryBlobClient  = _hostBlobServiceClient;

            // Important: We're using the storage account of the function target here, which is the account that the
            // function the listener is for is targeting. This is the account that will be used
            // to read the trigger blob.
            var targetBlobClient  = _dataBlobServiceClient;
            var targetQueueClient = _dataQueueServiceClient;

            string hostId = await _hostIdProvider.GetHostIdAsync(cancellationToken).ConfigureAwait(false);

            string hostBlobTriggerQueueName = HostQueueNames.GetHostBlobTriggerQueueName(hostId);
            var    hostBlobTriggerQueue     = primaryQueueClient.GetQueueClient(hostBlobTriggerQueueName);

            SharedQueueWatcher sharedQueueWatcher = _messageEnqueuedWatcherSetter;

            SharedBlobListener sharedBlobListener = _sharedContextProvider.GetOrCreateInstance <SharedBlobListener>(
                new SharedBlobListenerFactory(hostId, _hostBlobServiceClient, _exceptionHandler, _blobWrittenWatcherSetter, _loggerFactory.CreateLogger <BlobListener>()));

            // Register the blob container we wish to monitor with the shared blob listener.
            await RegisterWithSharedBlobListenerAsync(hostId, sharedBlobListener, primaryBlobClient,
                                                      hostBlobTriggerQueue, sharedQueueWatcher, cancellationToken).ConfigureAwait(false);

            // Create a "bridge" listener that will monitor the blob
            // notification queue and dispatch to the target job function.
            SharedBlobQueueListener sharedBlobQueueListener = _sharedContextProvider.GetOrCreateInstance <SharedBlobQueueListener>(
                new SharedBlobQueueListenerFactory(_hostQueueServiceClient, sharedQueueWatcher, hostBlobTriggerQueue,
                                                   _blobsOptions, _exceptionHandler, _loggerFactory, sharedBlobListener.BlobWritterWatcher, _functionDescriptor));
            var queueListener = new BlobListener(sharedBlobQueueListener);

            // the client to use for the poison queue
            // by default this should target the same storage account
            // as the blob container we're monitoring
            var poisonQueueClient = targetQueueClient;

            // Register our function with the shared blob queue listener
            RegisterWithSharedBlobQueueListenerAsync(sharedBlobQueueListener, targetBlobClient, poisonQueueClient);

            // check a flag in the shared context to see if we've created the singleton
            // shared blob listener in this host instance
            object singletonListenerCreated = false;

            if (!_sharedContextProvider.TryGetValue(SingletonBlobListenerScopeId, out singletonListenerCreated))
            {
                // Create a singleton shared blob listener, since we only
                // want a single instance of the blob poll/scan logic to be running
                // across host instances
                var singletonBlobListener = _singletonManager.CreateHostSingletonListener(
                    new BlobListener(sharedBlobListener), SingletonBlobListenerScopeId);
                _sharedContextProvider.SetValue(SingletonBlobListenerScopeId, true);

                return(new CompositeListener(singletonBlobListener, queueListener));
            }
            else
            {
                // We've already created the singleton blob listener
                // so just return our queue listener. Note that while we want the
                // blob scan to be singleton, the shared queue listener needs to run
                // on ALL instances so load can be scaled out
                return(queueListener);
            }
        }
        public async Task <IListener> CreateAsync(CancellationToken cancellationToken)
        {
            SharedQueueWatcher sharedQueueWatcher = _sharedContextProvider.GetOrCreateInstance <SharedQueueWatcher>(
                new SharedQueueWatcherFactory(_messageEnqueuedWatcherSetter));

            SharedBlobListener sharedBlobListener = _sharedContextProvider.GetOrCreateInstance <SharedBlobListener>(
                new SharedBlobListenerFactory(_hostAccount, _backgroundExceptionDispatcher, _blobWrittenWatcherSetter));

            // Note that these clients are intentionally for the storage account rather than for the dashboard account.
            // We use the storage, not dashboard, account for the blob receipt container and blob trigger queues.
            IStorageQueueClient queueClient = _hostAccount.CreateQueueClient();
            IStorageBlobClient  blobClient  = _hostAccount.CreateBlobClient();

            string hostId = await _hostIdProvider.GetHostIdAsync(cancellationToken);

            string        hostBlobTriggerQueueName = HostQueueNames.GetHostBlobTriggerQueueName(hostId);
            IStorageQueue hostBlobTriggerQueue     = queueClient.GetQueueReference(hostBlobTriggerQueueName);

            // Register the blob container we wish to monitor with the shared blob listener.
            await RegisterWithSharedBlobListenerAsync(hostId, sharedBlobListener, blobClient,
                                                      hostBlobTriggerQueue, sharedQueueWatcher, cancellationToken);

            // Create a "bridge" listener that will monitor the blob
            // notification queue and dispatch to the target job function.
            SharedBlobQueueListener sharedBlobQueueListener = _sharedContextProvider.GetOrCreateInstance <SharedBlobQueueListener>(
                new SharedBlobQueueListenerFactory(sharedQueueWatcher, queueClient, hostBlobTriggerQueue,
                                                   _queueConfiguration, _backgroundExceptionDispatcher, _trace, sharedBlobListener.BlobWritterWatcher));
            var queueListener = new BlobListener(sharedBlobQueueListener);

            // Important: We're using the "data account" here, which is the account that the
            // function the listener is for is targeting. This is the account that will be used
            // to read the trigger blob.
            IStorageBlobClient userBlobClient = _dataAccount.CreateBlobClient();

            // Register our function with the shared queue listener
            RegisterWithSharedBlobQueueListenerAsync(sharedBlobQueueListener, userBlobClient);

            // check a flag in the shared context to see if we've created the singleton
            // shared blob listener in this host instance
            object singletonListenerCreated = false;

            if (!_sharedContextProvider.TryGetValue(SingletonBlobListenerScopeId, out singletonListenerCreated))
            {
                // Create a singleton shared blob listener, since we only
                // want a single instance of the blob poll/scan logic to be running
                // across host instances
                var singletonBlobListener = _singletonManager.CreateHostSingletonListener(
                    new BlobListener(sharedBlobListener), SingletonBlobListenerScopeId);
                _sharedContextProvider.SetValue(SingletonBlobListenerScopeId, true);

                return(new CompositeListener(singletonBlobListener, queueListener));
            }
            else
            {
                // We've already created the singleton blob listener
                // so just return our queue listener. Note that while we want the
                // blob scan to be singleton, the shared queue listener needs to run
                // on ALL instances so load can be scaled out
                return(queueListener);
            }
        }