Beispiel #1
0
        public RabbitMQQueue(QueueName queueName, IQueueListener listener, IConnection connection,
            Encoding encoding = null, QueueOptions options = default(QueueOptions))
        {
            if (queueName == null) throw new ArgumentNullException("queueName");
            if (listener == null) throw new ArgumentNullException("listener");
            if (connection == null) throw new ArgumentNullException("connection");

            _queueName = queueName;
            _queueExchange = _queueName.GetExchangeName();
            _retryQueueName = queueName.GetRetryQueueName();
            _retryExchange = _queueName.GetRetryExchangeName();
            _deadLetterExchange = _queueName.GetDeadLetterExchangeName();

            _listener = listener;
            _connection = connection;
            _encoding = encoding ?? Encoding.UTF8;
            _ttl = options.TTL;
            _maxAttempts = Math.Max(options.MaxAttempts, 1);
            _retryDelay = options.RetryDelay < TimeSpan.Zero ? TimeSpan.Zero : options.RetryDelay;
            _cancellationTokenSource = new CancellationTokenSource();

            var autoAcknowledge = options.AutoAcknowledge;
            var concurrencyLimit = Math.Max(options.ConcurrencyLimit, 1);
            _consumers = new DurableConsumer[concurrencyLimit];
            for (var i = 0; i < _consumers.Length; i++)
            {
                var consumerTag = _queueName + "_" + i;
                _consumers[i] = new DurableConsumer(_connection, queueName, HandleDelivery, consumerTag,
                    autoAcknowledge);
            }
        }
        protected override Task AssertMessageStillQueuedForRetry(QueueName queue, Message message)
        {
            var retryQueue   = queue.GetRetryQueueName();
            var inRetryQueue = GetQueueDepth(retryQueue) > 0;

            return(Task.FromResult(inRetryQueue));
        }
        public async Task Given_Existing_Queue_When_New_Message_Queued_Then_Listener_Should_Fire()
        {
            var listenerCalledEvent = new ManualResetEvent(false);
            var queueName = new QueueName(Guid.NewGuid().ToString());
            var rmqQueueingService = new RabbitMQMessageQueueingService(RabbitMQUri);

            try
            {
                var mockListener = new Mock<IQueueListener>();
                mockListener.Setup(
                    x =>
                        x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(),
                            It.IsAny<CancellationToken>()))
                    .Callback<Message, IQueuedMessageContext, CancellationToken>((msg, ctx, ct) =>
                    {
                        ctx.Acknowledge();
                        listenerCalledEvent.Set();
                    })
                    .Returns(Task.FromResult(true));


                await rmqQueueingService.CreateQueue(queueName, mockListener.Object, new QueueOptions {MaxAttempts = 1});

                var message = new Message(new MessageHeaders
                {
                    {HeaderName.ContentType, "text/plain"},
                    {HeaderName.MessageId, Guid.NewGuid().ToString()}
                }, "Hello, world!");

                await rmqQueueingService.EnqueueMessage(queueName, message, Thread.CurrentPrincipal);
                await listenerCalledEvent.WaitOneAsync(TimeSpan.FromSeconds(1));

                var messageEqualityComparer = new MessageEqualityComparer();
                mockListener.Verify(
                    x =>
                        x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)),
                            It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once());

                Assert.That(GetQueueDepth(queueName), Is.EqualTo(0));
                Assert.That(GetQueueDepth(queueName.GetRetryQueueName()), Is.EqualTo(0));
            }
            finally
            {
                rmqQueueingService.Dispose();
                DeleteQueue(queueName);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Initializes a new <see cref="RabbitMQQueue"/>
        /// </summary>
        /// <param name="connection">The connection to the RabbitMQ server</param>
        /// <param name="queueName">The name of the queue</param>
        /// <param name="listener">The listener that will receive new messages off of the queue</param>
        /// <param name="encoding">(Optional) The encoding to use when converting serialized message
        ///     content to byte streams</param>
        /// <param name="options">(Optional) Queueing options</param>
        /// <param name="diagnosticService">(Optional) The service through which diagnostic events
        ///     are reported and processed</param>
        /// <param name="securityTokenService">(Optional) The message security token
        ///     service to use to issue and validate security tokens for persisted messages.</param>
        /// <param name="messageEncryptionService"></param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="queueName"/>,
        /// <paramref name="listener"/>, or <paramref name="connection"/> is <c>null</c></exception>
        public RabbitMQQueue(IConnection connection,
                             QueueName queueName, IQueueListener listener,
                             Encoding encoding, QueueOptions options,
                             IDiagnosticService diagnosticService,
                             ISecurityTokenService securityTokenService,
                             IMessageEncryptionService messageEncryptionService)
        {
            _queueName          = queueName ?? throw new ArgumentNullException(nameof(queueName));
            _queueExchange      = _queueName.GetExchangeName();
            _retryQueueName     = queueName.GetRetryQueueName();
            _retryExchange      = _queueName.GetRetryExchangeName();
            _deadLetterExchange = _queueName.GetDeadLetterExchangeName();

            _listener             = listener ?? throw new ArgumentNullException(nameof(listener));
            _connection           = connection ?? throw new ArgumentNullException(nameof(connection));
            _securityTokenService = securityTokenService ?? throw new ArgumentNullException(nameof(securityTokenService));
            _encoding             = encoding ?? Encoding.UTF8;

            var myOptions = options ?? new QueueOptions();

            _ttl             = myOptions.TTL;
            _autoAcknowledge = myOptions.AutoAcknowledge;
            _maxAttempts     = myOptions.MaxAttempts;
            _retryDelay      = myOptions.RetryDelay;
            _isDurable       = myOptions.IsDurable;

            var concurrencyLimit = myOptions.ConcurrencyLimit;

            _cancellationTokenSource  = new CancellationTokenSource();
            _diagnosticService        = diagnosticService ?? DiagnosticService.DefaultInstance;
            _messageEncryptionService = messageEncryptionService;

            var consumerTag = _queueName;

            _consumer = new DurableConsumer(_connection, queueName, HandleDelivery, consumerTag,
                                            concurrencyLimit, _autoAcknowledge, _diagnosticService);
        }
        public async Task Given_10_Existing_Messages_10_New_Messages_Then_Listener_Should_Fire_For_All_20_Messages()
        {
            var queueName = new QueueName(Guid.NewGuid().ToString());
            var rmqQueueingService = new RabbitMQMessageQueueingService(RabbitMQUri);

            try
            {
                var existingMessages = Enumerable.Range(1, 10)
                    .Select(i => new Message(new MessageHeaders
                    {
                        {HeaderName.ContentType, "text/plain"},
                        {HeaderName.MessageId, Guid.NewGuid().ToString()}
                    }, "Hello, world! (" + i + ")"))
                    .ToList();

                await Task.WhenAll(existingMessages.Select(msg => StageExistingMessage(msg, queueName)));

                var newMessages = Enumerable.Range(11, 10)
                    .Select(i => new Message(new MessageHeaders
                    {
                        {HeaderName.ContentType, "text/plain"},
                        {HeaderName.MessageId, Guid.NewGuid().ToString()}
                    }, "Hello, world! (" + i + ")"))
                    .ToList();

                var listenerCountdown = new CountdownEvent(existingMessages.Count + newMessages.Count);

                var mockListener = new Mock<IQueueListener>();
                mockListener.Setup(
                    x =>
                        x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(),
                            It.IsAny<CancellationToken>()))
                    .Callback<Message, IQueuedMessageContext, CancellationToken>((msg, ctx, ct) =>
                    {
                        ctx.Acknowledge();
                        listenerCountdown.Signal();
                    })
                    .Returns(Task.FromResult(true));

                await rmqQueueingService.CreateQueue(queueName, mockListener.Object, new QueueOptions {MaxAttempts = 1});

                await Task.WhenAll(newMessages.Select(msg =>
                    rmqQueueingService.EnqueueMessage(queueName, msg, Thread.CurrentPrincipal)));

                var timedOut = !await listenerCountdown.WaitHandle.WaitOneAsync(TimeSpan.FromSeconds(10));

                Assert.That(timedOut, Is.False, "Timed out waiting for listeners to be called");

                var messageEqualityComparer = new MessageEqualityComparer();
                var allmessages = existingMessages.Union(newMessages);
                foreach (var message in allmessages)
                {
                    mockListener.Verify(
                        x =>
                            x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)),
                                It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once());
                }

                Assert.That(GetQueueDepth(queueName), Is.EqualTo(0));
                Assert.That(GetQueueDepth(queueName.GetRetryQueueName()), Is.EqualTo(0));
            }
            finally
            {
                
                rmqQueueingService.Dispose();
                DeleteQueue(queueName);
            }
        }
        private static void DeleteQueue(QueueName queueName)
        {
            var connectionFactory = new ConnectionFactory { Uri = RabbitMQUri.ToString() };
            using (var connection = connectionFactory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // We have to declare the queue as a persistence queue because this is 
                // called before the queue is created by the RabbitMQQueueingService
                var queueExchange = queueName.GetExchangeName();
                var retryExchange = queueName.GetRetryExchangeName();
                var deadLetterExchange = queueName.GetDeadLetterExchangeName();
                var retryQueueName = queueName.GetRetryQueueName();

                channel.QueueDeleteNoWait(queueName, false, false);
                channel.QueueDeleteNoWait(retryQueueName, false, false);
                channel.ExchangeDeleteNoWait(queueExchange, false);
                channel.ExchangeDeleteNoWait(retryExchange, false);
                channel.ExchangeDeleteNoWait(deadLetterExchange, false);
            }
        }
        public async Task Given_Auto_Acknowledge_Queue_When_Not_Acknowledged_Then_Message_Should_Be_Deleted()
        {
            var queueName = new QueueName(Guid.NewGuid().ToString());
            var rmqQueueingService = new RabbitMQMessageQueueingService(RabbitMQUri);

            try
            {
                var listenerCalledEvent = new ManualResetEvent(false);
                var mockListener = new Mock<IQueueListener>();
                mockListener.Setup(x =>
                    x.MessageReceived(It.IsAny<Message>(), It.IsAny<IQueuedMessageContext>(),
                        It.IsAny<CancellationToken>()))
                    .Callback<Message, IQueuedMessageContext, CancellationToken>(
                        (msg, ctx, ct) => { listenerCalledEvent.Set(); })
                    .Returns(Task.FromResult(true));

                await rmqQueueingService.CreateQueue(queueName, mockListener.Object, new QueueOptions {AutoAcknowledge = true});

                var message = new Message(new MessageHeaders
                {
                    {HeaderName.ContentType, "text/plain"},
                    {HeaderName.MessageId, Guid.NewGuid().ToString()}
                }, "Hello, world!");

                await rmqQueueingService.EnqueueMessage(queueName, message, Thread.CurrentPrincipal);
                await listenerCalledEvent.WaitOneAsync(TimeSpan.FromSeconds(1));

                // The listener is called before the file is deleted, so there is a possible
                // race condition here.  Wait for a second to allow the delete to take place
                // before enumerating the files to see that they were actually deleted.
                await Task.Delay(TimeSpan.FromSeconds(1));

                var messageEqualityComparer = new MessageEqualityComparer();
                mockListener.Verify(x =>
                    x.MessageReceived(It.Is<Message>(m => messageEqualityComparer.Equals(m, message)),
                        It.IsAny<IQueuedMessageContext>(), It.IsAny<CancellationToken>()), Times.Once());

                Assert.That(GetQueueDepth(queueName), Is.EqualTo(0));
                Assert.That(GetQueueDepth(queueName.GetRetryQueueName()), Is.EqualTo(0));
            }
            finally
            {
                rmqQueueingService.Dispose();
                DeleteQueue(queueName);
            }
        }