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