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