.Net RabbitMQ客户端Subscriber.Next挂起

时间:2015-07-23 17:16:04

标签: c# .net rabbitmq amqp

我在Windows服务中使用RabbitMQ .net客户端。我有大量的邮件批量发送然后被处理,然后输出放在另一个队列上。我正在创建心跳为30的连接工厂,然后在连接或订户丢失时创建连接。在生产中,我的代码可能在大多数情况下都有效。但是,在我的集成测试中,我知道它在大多数情况下失败了。这是我的代码:

public void ReceiveAll(Func<IDictionary<ulong, byte[]>, IOnStreamWatchResult> onReceiveAllCallback, int batchSize, CancellationToken cancellationToken)
{
    IModel channel = null;
    Subscription subscription = null;

    while (!cancellationToken.IsCancellationRequested)
    {
        if (subscription == null || subscription.Model.IsClosed)
        {
            channel = _channelFactory.CreateChannel(ref _connection, _messageQueueConfig, _connectionFactory);
            // This instructs the channel to not prefetch more than batch count into shared queue
            channel.BasicQos(0, Convert.ToUInt16(batchSize), false);
            subscription = new Subscription(channel, _messageQueueConfig.Queue, false);
        }

        try
        {
            BasicDeliverEventArgs message;
            var dequeuedMessages = new Dictionary<ulong, byte[]>();
            do
            {
                if (subscription.Next(_messageQueueConfig.DequeueTimeout.Milliseconds, out message))
                {
                    if (message == null)
                    {
                        // This means channel is closed and the messages in shared queue would get moved back to ready state
                        DisposeChannelAndSubcription(ref channel, ref subscription);
                        ReceiveAll(onReceiveAllCallback, batchSize, cancellationToken);
                    }
                    else
                    {
                        dequeuedMessages.Add(message.DeliveryTag, message.Body);
                    }
                }
            } while (message != null && batchSize > dequeuedMessages.Count && !cancellationToken.IsCancellationRequested);

            if (cancellationToken.IsCancellationRequested)
            {
                if (dequeuedMessages.Any())
                {
                    NackUnProcessedMessages(subscription, dequeuedMessages.Keys);
                }
                DisposeChannelAndSubcription(ref channel, ref subscription);
                dequeuedMessages.Clear();
                break;
            }

            try
            {
                var onStreamWatchResult = onReceiveAllCallback(dequeuedMessages);
                AckProcessedMessages(subscription, onStreamWatchResult.Processed);
                NackUnProcessedMessages(subscription, onStreamWatchResult.UnProcessed);
                dequeuedMessages.Clear();
            }
            catch(Exception unhandledException)
            {
                NackUnProcessedMessages(subscription, dequeuedMessages.Keys);
            }
        }
        catch (EndOfStreamException endOfStreamException)
        {
            DisposeChannelAndSubcription(ref channel, ref subscription);
        }
        catch (OperationInterruptedException operationInterruptedException)
        {
            DisposeChannelAndSubcription(ref channel, ref subscription);
        }
    }
}

批量大小设置为4,因为我在集成测试中放了4条消息,这只是我在运行单元测试后运行的一个Windows服务。

这里的问题是,几乎总是,订阅者预取4条消息,如预期的那样,对前两个迭代返回true。但是之后它返回false。我相信这种情况正在发生,因为我的消息没有得到正确的解决。在我的集成测试中,我确认2和nack 2消息,然后再次读取2个nacked消息以清除队列。但是,在nacking之后,消息不会返回就绪状态,因此测试会挂起。我在这做错了什么?我不理解nacking文档中的某些内容吗?这是我的代码:

subscription.Model.BasicNack(deliveryTag, false, true);

0 个答案:

没有答案