public async Task Should_not_attach_attachments_for_other_commands()
        {
            //arrange
            var message       = new TestCommand();
            var nextProcessor = new Mock <IMessageProcessor>();
            var stateHandler  = new Mock <IMessageStateHandler <TestCommand> >();

            stateHandler.Setup(x => x.GetMessageAsync()).ReturnsAsync(message);
            var attachmentProvider = new Mock <IMessageAttachmentProvider>();

            attachmentProvider.Setup(x => x.GetAttachmentAsync(AutoMessageMapper.GetQueueName <TestCommand>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(default(IMessageAttachment));
            var middleware = new AttachmentMiddleware(attachmentProvider.Object);
            //act
            await middleware.ProcessAsync(stateHandler.Object, Mock.Of <IPipelineInformation>(), nextProcessor.Object, CancellationToken.None);

            //assert
            attachmentProvider.Verify(x => x.GetAttachmentAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Never);
            nextProcessor.Verify(x => x.ProcessAsync(stateHandler.Object, CancellationToken.None), Times.Once);
        }
        public async Task Should_delete_attachment_when_finished()
        {
            //arrange
            var message       = new AttachmentCommand();
            var nextProcessor = new Mock <IMessageProcessor>();
            var stream        = new MemoryStream(Encoding.UTF8.GetBytes("this is a stream"));
            var attachment    = new MessageAttachment("test.txt", "text/plain", stream);
            var stateHandler  = new Mock <IMessageStateHandler <AttachmentCommand> >();

            stateHandler.Setup(x => x.GetMessageAsync()).ReturnsAsync(message);
            stateHandler.Setup(x => x.MessageProperties).Returns(new Dictionary <string, string> {
                { AttachmentUtility.AttachmentKey, "89BDF3DB-896C-448D-A84E-872CBA8DBC9F" }
            });
            var attachmentProvider = new Mock <IMessageAttachmentProvider>();

            attachmentProvider.Setup(x => x.GetAttachmentAsync(AutoMessageMapper.GetQueueName <AttachmentCommand>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(attachment);
            var middleware = new AttachmentMiddleware(attachmentProvider.Object);
            //act
            await middleware.ProcessAsync(stateHandler.Object, Mock.Of <IPipelineInformation>(), nextProcessor.Object, CancellationToken.None);

            //assert
            attachmentProvider.Verify(x => x.DeleteAttachmentAsync(AutoMessageMapper.GetQueueName <AttachmentCommand>(), It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Once);
        }
Пример #3
0
 public RedisCommandChannelReceiver(IConnectionMultiplexer connectionMultiplexer, IProcessingSettings settings, IMessageSerializer serializer, RedisConfiguration configuration, IHostConfiguration hostConfiguration, IMessageProcessor processor)
     : base(connectionMultiplexer, AutoMessageMapper.GetQueueName <T>(), settings, serializer, configuration, hostConfiguration, processor)
 {
 }
Пример #4
0
        private SubscriptionClient CreateSubscriptionClient <T>(string subscriptionName) where T : IEvent
        {
            var topicName = AutoMessageMapper.GetQueueName <T>();

            return(new SubscriptionClient(_connectionString, topicName, subscriptionName, ReceiveMode.PeekLock, RetryPolicy.Default));
        }
Пример #5
0
        private TopicClient CreateTopicClient <T>() where T : IEvent
        {
            var topicName = AutoMessageMapper.GetQueueName <T>();

            return(new TopicClient(_connectionString, topicName, RetryPolicy.Default));
        }
Пример #6
0
        private QueueClient CreateQueueClient <T>() where T : ICommand
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            return(new QueueClient(_connectionString, queueName, ReceiveMode.PeekLock, RetryPolicy.Default));
        }
Пример #7
0
 public RedisEventChannelReceiver(IConnectionMultiplexer connectionMultiplexer, IProcessingSettings settings, IMessageSerializer serializer, IEventSubscription <T> subscription, RedisConfiguration configuration, IHostConfiguration hostConfiguration, IMessageProcessor processor)
     : base(connectionMultiplexer, RedisQueueConventions.GetSubscriptionQueueName(AutoMessageMapper.GetQueueName <T>(), subscription.Name), settings, serializer, configuration, hostConfiguration, processor)
 {
     _subscription       = subscription;
     _redisConfiguration = configuration;
 }
Пример #8
0
 private IStorageQueueClient GetClient <T>() where T : class, ICommand
 {
     return(_queueClients.GetOrAdd(typeof(T), type =>
     {
         var serializer = _options.MessageSerializer;
         var mapping = AutoMessageMapper.GetMapping <T>();
         if (mapping is ICustomMessageSerializer customSerializer)
         {
             serializer = customSerializer.MessageSerializer;
         }
         return new StorageQueueClient(_options, serializer, _attachmentProvider, AutoMessageMapper.GetQueueName <T>());
     }));
 }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _cancellationToken = cancellationToken;
            _client            = await _clientFactory.GetReceiverClient <TTopic, IEventSubscription <TTopic> >(_subscription, new ServiceBusProcessorOptions
            {
                AutoCompleteMessages       = false,
                MaxAutoLockRenewalDuration = Settings.MessageLockTimeout,
                MaxConcurrentCalls         = Settings.MaxConcurrentCalls,
                PrefetchCount = Settings.PrefetchCount,
                ReceiveMode   = ServiceBusReceiveMode.PeekLock
            }).ConfigureAwait(false);


            var topicName = AutoMessageMapper.GetQueueName <TTopic>();

            if (!await _managementClient.TopicExistsAsync(topicName, cancellationToken).ConfigureAwait(false))
            {
                try
                {
                    var serviceBusCreationOptions = GetServiceBusCreationOptions();

                    await _managementClient.CreateTopicAsync(new CreateTopicOptions(topicName)
                    {
                        EnablePartitioning      = serviceBusCreationOptions.EnablePartitioning,
                        EnableBatchedOperations = serviceBusCreationOptions.EnableBatchedOperations,
                        SupportOrdering         = serviceBusCreationOptions.SupportOrdering
                    }, cancellationToken).ConfigureAwait(false);
                }
                catch (ServiceBusException e)
                {
                    _log.Error(e, "Failed to create topic {TopicName}", topicName);
                    throw;
                }
            }
            if (!await _managementClient.SubscriptionExistsAsync(topicName, _subscription.Name, cancellationToken).ConfigureAwait(false))
            {
                try
                {
                    var serviceBusCreationOptions = GetServiceBusCreationOptions();

                    await _managementClient.CreateSubscriptionAsync(new CreateSubscriptionOptions(topicName, _subscription.Name)
                    {
                        EnableBatchedOperations = serviceBusCreationOptions.EnableBatchedOperations
                    }, cancellationToken).ConfigureAwait(false);
                }
                catch (ServiceBusException e)
                {
                    _log.Error(e, "Failed to create subscription {TopicName} {SubscriptionName}", topicName, _subscription.Name);
                    throw;
                }
            }

            _deadLetterLimit = Settings.DeadLetterDeliveryLimit;

            _client.ProcessMessageAsync += ClientOnProcessMessageAsync;
            _client.ProcessErrorAsync   += ClientOnProcessErrorAsync;

            await _client.StartProcessingAsync(cancellationToken);

#pragma warning disable 4014
            // ReSharper disable once MethodSupportsCancellation
            Task.Run(async() =>
            {
                _cancellationToken.WaitHandle.WaitOne();
                //Cancellation requested
                try
                {
                    _log.Information($"Closing ServiceBus channel receiver for {typeof(TTopic).Name}");
                    await _client.CloseAsync(CancellationToken.None);
                }
                catch (Exception)
                {
                    //Swallow
                }
            });
#pragma warning restore 4014
        }
Пример #10
0
 private IStorageQueueClient GetClient <T>() where T : class, ICommand
 {
     return(_queueClients.GetOrAdd(typeof(T), type => new StorageQueueClient(_options, AutoMessageMapper.GetQueueName <T>())));
 }
Пример #11
0
        public void Should_find_registered_type()
        {
            var name = AutoMessageMapper.GetQueueName(typeof(RegisteredCommand));

            name.Should().Be("queue");
        }
Пример #12
0
        public void Should_find_registered_generic()
        {
            var name = AutoMessageMapper.GetQueueName <RegisteredCommand>();

            name.Should().Be("queue");
        }
        internal async Task PumpAsync <T>(Func <StorageQueueMessage, CancellationToken, Task> action, CancellationToken cancellationToken) where T : IStorageQueueCommand
        {
            var messagesFound = false;

            try
            {
                var queueName = AutoMessageMapper.GetQueueName <T>();

                var prefetchCount = _settings.PrefetchCount > 0 ? _settings.PrefetchCount : 1;

                TimeSpan visibilityTimeout;
                if (_settings is IExtendMessageLockTimeout extendMessageLockTimeout)
                {
                    visibilityTimeout = extendMessageLockTimeout.ExtensionDuration;
                }
                else
                {
                    visibilityTimeout = _settings.MessageLockTimeout;
                }

                //Make sure the lock still exist when the process is cancelled by token, otherwise the message cannot be abandoned
                visibilityTimeout += TimeSpan.FromMinutes(2);

                var messages = await _storageQueueClient.GetMessagesAsync <T>(prefetchCount, visibilityTimeout).ConfigureAwait(false);

                messagesFound = messages.Any();

                _log.Debug("Prefetched {MessageCount} messages from {QueueName} in {Name}", messages.Count, queueName, nameof(StorageQueueMessagePump));

                foreach (var message in messages)
                {
                    var timeoutToken = new CancellationTokenSource(_settings.MessageLockTimeout);
                    var linkedToken  = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token);
                    try
                    {
                        _log.Debug("Processing {@Message} in {Name}", message, nameof(StorageQueueMessagePump));
                        _log.Debug("{ThreadCount} remaining threads that can process messages in {QueueName} in {Name}", _maxConcurrent.CurrentCount, queueName, nameof(StorageQueueMessagePump));

                        await _maxConcurrent.WaitAsync(timeoutToken.Token).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException operationCanceledException)
                    {
                        _log.Debug(operationCanceledException, "Operation canceled for {@Message} in {QueueName} in {Name}", message, queueName, nameof(StorageQueueMessagePump));

                        //If we are still waiting when the message has not been scheduled for execution timeouts

                        continue;
                    }
#pragma warning disable 4014 //No need to await the result, let's keep the pump going
                    Task.Run(async() => await action.Invoke(message, linkedToken.Token).ConfigureAwait(false), timeoutToken.Token)
                    .ContinueWith(task =>
                    {
                        _maxConcurrent.Release();
                        timeoutToken.Dispose();
                        linkedToken.Dispose();
                    }).ConfigureAwait(false);
#pragma warning restore 4014
                }
            }
            catch (Exception e)
            {
                _log.Error(e, "StorageQueueMessagePump error in {MessageType}", typeof(T));
            }
            finally
            {
                if (!messagesFound)
                {
                    //Only delay pump if no messages were found
                    await Task.Delay(_pollingInterval).ConfigureAwait(false);
                }
            }
        }
Пример #14
0
        public Task SendAsync <T>(IEnumerable <T> messages) where T : IRedisCommand
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            return(SendAsync <T>(messages.ToList(), queueName));
        }
Пример #15
0
        public Task SendAsync <T>(T message) where T : IRedisCommand
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            return(SendAsync(message, queueName));
        }