private IServiceBusCreationOptions GetServiceBusCreationOptions()
        {
            var queueMapping    = AutoMessageMapper.GetMapping <T>();
            var creationOptions = queueMapping as IServiceBusCreationOptions;

            return(creationOptions ?? _configuration.DefaultCreationOptions);
        }
Пример #2
0
        private async Task <ServiceBusMessage> CreateMessageAsync <T>(T body) where T : IMessage
        {
            var serializer = GetSerializer <T>();
            var message    = new ServiceBusMessage(serializer.Serialize(body))
            {
                ContentType = serializer.ContentType
            };

            if (typeof(ICommandWithAttachment).IsAssignableFrom(typeof(T)))
            {
                if (_attachmentProvider == null)
                {
                    throw new AttachmentProviderMissingException();
                }

                var attachmentMessage = (ICommandWithAttachment)body;
                if (attachmentMessage.Attachment != null)
                {
                    var attachmentIds = new List <string>();
                    var id            = Guid.NewGuid().ToString("N");
                    var queueName     = AutoMessageMapper.GetQueueName <T>();
                    await _attachmentProvider.UploadAttachmentAsync(queueName, id, attachmentMessage.Attachment).ConfigureAwait(false);

                    attachmentIds.Add(id);
                    message.ApplicationProperties[AttachmentUtility.AttachmentKey] = string.Join(",", attachmentIds);
                }
            }

            return(message);
        }
        public async Task Should_attach_attachment_when_command_have_attachment()
        {
            //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
            stream.CanRead.Should().BeFalse("It should have been disposed");
            message.Attachment.Filename.Should().Be("test.txt");
            message.Attachment.ContentType.Should().Be("text/plain");
            nextProcessor.Verify(x => x.ProcessAsync(stateHandler.Object, CancellationToken.None), Times.Once);
        }
Пример #4
0
        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            var db = ConnectionMultiplexer.GetDatabase(_redisConfiguration.DatabaseId);
            await db.SetAddAsync(RedisQueueConventions.GetSubscriptionKey(AutoMessageMapper.GetQueueName <T>()), _subscription.Name).ConfigureAwait(false);

            await base.StartAsync(cancellationToken).ConfigureAwait(false);
        }
Пример #5
0
        public async Task ProcessAsync <T>(IMessageStateHandler <T> messageStateHandler, IPipelineInformation pipelineInformation, IMessageProcessor next, CancellationToken cancellationToken) where T : class, IMessage
        {
            IMessageAttachment attachment = null;
            var queueName = AutoMessageMapper.GetQueueName <T>();

            try
            {
                string attachmentId = null;
                if (typeof(ICommandWithAttachment).IsAssignableFrom(typeof(T)))
                {
                    attachmentId = AttachmentUtility.GetAttachmentIds(messageStateHandler.MessageProperties).FirstOrDefault();
                    if (!string.IsNullOrEmpty(attachmentId))
                    {
                        attachment = await _attachmentProvider.GetAttachmentAsync(queueName, attachmentId, cancellationToken).ConfigureAwait(false);

                        var message = (ICommandWithAttachment)await messageStateHandler.GetMessageAsync().ConfigureAwait(false);

                        message.Attachment = attachment;
                    }
                }

                await next.ProcessAsync(messageStateHandler, cancellationToken).ConfigureAwait(false);

                if (attachment != null)
                {
                    attachment.Stream?.Dispose();
                    await _attachmentProvider.DeleteAttachmentAsync(queueName, attachmentId, cancellationToken).ConfigureAwait(false);
                }
            }
            finally
            {
                attachment?.Stream?.Dispose();
            }
        }
Пример #6
0
        private ServiceBusProcessor CreateReceiverClient <T>(ServiceBusProcessorOptions options) where T : ICommand
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();
            var client    = new ServiceBusClient(_connectionString);

            return(client.CreateProcessor(queueName, options));
        }
Пример #7
0
        private ServiceBusProcessor CreateSubscriptionClient <T>(string subscriptionName, ServiceBusProcessorOptions options) where T : IEvent
        {
            var topicName = AutoMessageMapper.GetQueueName <T>();
            var client    = new ServiceBusClient(_connectionString);

            return(client.CreateProcessor(topicName, subscriptionName, options));
        }
Пример #8
0
        private ServiceBusSender CreateQueueClient <T>() where T : IMessage
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();
            var client    = new ServiceBusClient(_connectionString);

            return(client.CreateSender(queueName));
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _cancellationToken = cancellationToken;
            _client            = await _clientFactory.GetReceiverClient <T>(new ServiceBusProcessorOptions
            {
                AutoCompleteMessages       = false,
                MaxAutoLockRenewalDuration = Settings.MessageLockTimeout,
                MaxConcurrentCalls         = Settings.MaxConcurrentCalls,
                PrefetchCount = Settings.PrefetchCount,
                ReceiveMode   = ServiceBusReceiveMode.PeekLock
            }).ConfigureAwait(false);

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

            if (!await _managementClient.QueueExistsAsync(queueName, _cancellationToken).ConfigureAwait(false))
            {
                try
                {
                    var serviceBusCreationOptions = GetServiceBusCreationOptions();

                    await _managementClient.CreateQueueAsync(new CreateQueueOptions(queueName)
                    {
                        EnablePartitioning      = serviceBusCreationOptions.EnablePartitioning,
                        EnableBatchedOperations = serviceBusCreationOptions.EnableBatchedOperations
                    }, cancellationToken).ConfigureAwait(false);
                }
                catch (ServiceBusException e)
                {
                    _log.Error(e, "Failed to create queue {QueueName}", queueName);
                    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(T).Name}");
                    await _client.CloseAsync(CancellationToken.None);
                }
                catch (Exception)
                {
                    //Swallow
                }
            });
#pragma warning restore 4014
        }
        private async Task Initialize()
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            _storageQueueClient = new StorageQueueClient(_storageOptions, queueName);
            await _storageQueueClient.CreateIfNotExistsAsync().ConfigureAwait(false);

            _messagePump = new StorageQueueMessagePump(_storageQueueClient, Settings, _hostConfiguration.Log);
        }
Пример #11
0
        private IMessageSerializer GetSerializer(ITransportChannelFactory channelFactory, Type messageType)
        {
            var mapping = AutoMessageMapper.GetMapping(messageType);

            if (mapping is ICustomMessageSerializer serializer)
            {
                return(serializer.MessageSerializer);
            }

            return(channelFactory.Configuration.MessageSerializer);
        }
Пример #12
0
        public async Task PublishAsync <T>(T message) where T : IRedisEvent
        {
            var db            = _multiplexer.GetDatabase(_configuration.DatabaseId);
            var queueName     = AutoMessageMapper.GetQueueName <T>();
            var subscriptions = await db.SetMembersAsync(RedisQueueConventions.GetSubscriptionKey(queueName)).ConfigureAwait(false);

            if (subscriptions == null)
            {
                return;
            }
            await Task.WhenAll(subscriptions.Select(sub => SendAsync(message, RedisQueueConventions.GetSubscriptionQueueName(queueName, sub)))).ConfigureAwait(false);
        }
Пример #13
0
 private IMessageSerializer GetSerializer <T>() where T : IMessage
 {
     return(_serializers.GetOrAdd(typeof(T), type =>
     {
         var mapper = AutoMessageMapper.GetMapping <T>();
         if (mapper is ICustomMessageSerializer serializer)
         {
             return serializer.MessageSerializer;
         }
         return _configuration.MessageSerializer;
     }));
 }
Пример #14
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>());
     }));
 }
        internal async Task PumpAsync <T>(Func <StorageQueueMessage, CancellationToken, Task> action) where T : IStorageQueueCommand
        {
            var messagesFound = false;

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

                var prefetchCount = _settings.PrefetchCount > 0 ? _settings.PrefetchCount : 1;
                var messages      = await _storageQueueClient.GetMessagesAsync <T>(prefetchCount, _settings.MessageLockTimeout).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 cts = new CancellationTokenSource(_settings.MessageLockTimeout);
                    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(cts.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, cts.Token).ConfigureAwait(false), cts.Token).ContinueWith(task => _maxConcurrent.Release()).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);
                }
            }
        }
Пример #16
0
        public async Task ProcessAsync <T>(IMessageStateHandler <T> messageStateHandler, IPipelineInformation pipelineInformation, IMessageProcessor next, CancellationToken cancellationToken) where T : class, IMessage
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            var log = pipelineInformation?.HostConfiguration?.Log;

            log?.Debug("{ThreadCount} remaining threads that can process messages in {QueueName} in {Name}", _semaphoreQueue.CurrentCount, queueName, nameof(ThrottlingMiddleware));

            await _semaphoreQueue.WaitAsync(cancellationToken).ConfigureAwait(false);

            try
            {
                await next.ProcessAsync(messageStateHandler, cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                _semaphoreQueue.Release();
            }
        }
        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, nextProcessor.Object, CancellationToken.None);

            //assert
            attachmentProvider.Verify(x => x.DeleteAttachmentAsync(AutoMessageMapper.GetQueueName <AttachmentCommand>(), It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Once);
        }
Пример #19
0
 private IStorageQueueClient GetClient <T>() where T : class, ICommand
 {
     return(_queueClients.GetOrAdd(typeof(T), type => new StorageQueueClient(_options, AutoMessageMapper.GetQueueName <T>())));
 }
Пример #20
0
        public Task SendAsync <T>(T message) where T : IRedisCommand
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            return(SendAsync(message, queueName));
        }
Пример #21
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)
 {
 }
Пример #22
0
        public Task SendAsync <T>(IEnumerable <T> messages) where T : IRedisCommand
        {
            var queueName = AutoMessageMapper.GetQueueName <T>();

            return(SendAsync <T>(messages.ToList(), queueName));
        }
Пример #23
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));
        }
Пример #24
0
        private TopicClient CreateTopicClient <T>() where T : IEvent
        {
            var topicName = AutoMessageMapper.GetQueueName <T>();

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

            return(new QueueClient(_connectionString, queueName, ReceiveMode.PeekLock, RetryPolicy.Default));
        }
        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);
                }
            }
        }
Пример #27
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;
 }
Пример #28
0
        public void Should_find_registered_generic()
        {
            var name = AutoMessageMapper.GetQueueName <RegisteredCommand>();

            name.Should().Be("queue");
        }
Пример #29
0
        public void Should_find_registered_type()
        {
            var name = AutoMessageMapper.GetQueueName(typeof(RegisteredCommand));

            name.Should().Be("queue");
        }